2017-08-14 1 views
0

私はJavascriptを使って解析したいが、別のJavascript関数を実行する前に外部XMLファイルを持っている。 XMLファイルの値をグローバルオブジェクトに格納したい。問題は、同期解析が非推奨であるため、XMLを非同期で解析していることです。 XMLが解析される前にJavascript関数が実行されるので、グローバル変数がundefinedであるため、エラーが発生します。Javascript関数の前にXMLを解析する

XMLファイルを1つのJavascriptファイルで解析し、次にdefer属性を使用して別のファイルで関数を呼び出してみました。しかし、これはすべてのスクリプトが実行された後でもパーサが実行されるために機能します。私は困惑している!私はまた、JavaScript関数でsetTimeout()メソッドを使用しようとしましたが、最終的には未定義の値も生成されます。

私は、スクリプトの実行順序と関係があるスタックオーバーフローに関するいくつかの質問を読んだ。私は、この問題が実行命令について多くのことを教えてくれたと言います。

注:ここに示したものよりも多くのスクリプトがあります。そのため、XMLファイルの解析方法とその値が未定義として保存されることを説明するために必要なものを追加しました。

更新:私は中立的な方法で使用できるように、この方法でパーサを記述しました。パーサは何度も使用され、使用に応じて異なるイベントが発生するたびに使用されます。そのため、私はonreadystatechange関数に特定の関数を追加していません。

XMLファイルを解析するのに、XML DOMXMLHttpRequestを使用しています。

// Parser 
function load_prs(data_func , loc , tag) 
{ 
var parsreq = new XMLHttpRequest() ; 

parsreq.onreadystatechange = function() { 
if ((parsreq.readyState === 4) && (parsreq.status === 200)) 
    { 
    var xml = parsreq.responseXML ; 
    var listing = xml.getElementsByTagName(tag) ; 
    var list = listing[0].children ; 

    // Call a specific function using the data_func argument 
    data_func(list) ; 
    } 
} ; 

parsreq.open("GET" , loc + ".xml" , true) ; 
parsreq.send() ; 
} 

解析する関数を呼び出します。

load_prs(load_playlist , "nd/playlist" , "playlist") ; 

機能load_playlist()はグローバルオブジェクトにXML値を代入します。

// The global object with name/value pairs 
var playlist_obj = { band: "" , album: "" , title: "" } ; 

// Array for storing playlist_obj 
var playlist = [] ; 

// Function to get values from the XML document 
function get_val(tar , tag) { return tar.getElementsByTagName(tag)[0].childNodes[0].nodeValue ; } 

// Function passed to load_prs() 
function load_playlist(list) 
{ 
var px ; 
var plen = list.length ; 

// Loop through each item in the XML document and get values 
for (px = 0 ; px < plen ; px++) 
    { 
    playlist_obj.band = get_val(list[px] , "band") ; 
    playlist_obj.album = get_val(list[px] , "album") ; 
    playlist_obj.title = get_val(list[px] , "title") ; 

    // Push playlist_obj to the global array for later use 
    playlist.push(playlist_obj) ; 
    } 
} 

私のXMLファイル:

<?xml version="1.0" encoding="UTF-8"?> 
<playlist> 
<track> 
    <band>Desecresy</band> 
    <album>Stoic Death</album> 
    <title>Funeral Odyssey</title> 
</track> 
<track> 
    <band>Catacombs</band> 
    <album>In the Depths of R'lyeh</album> 
    <title>Where No Light Hath Shone...</title> 
</track> 
</playlist> 

を私が試してみるとき同じスクリプト内のグローバルオブジェクトにアクセスする別の関数を呼び出すと、私は未定義の値を取得します。 の前にload_band()が実行されているため、var tundefinedを返します。

+0

もう1つのことを指摘してください。すべてのスクリプトの実行が終了すると、パーサーはグローバルオブジェクトに値を格納して格納します。しかし、 'load_band'関数が後で呼び出される前にそれを行う必要があります。 'load_band'関数が呼び出されるとエラーが発生します。 – Xavier

+1

さて、あなたは 'load_band()'をonreadystatechangeハンドラのコードにそれぞれ移動させなければなりません。一般的に、最近では、このような作業を楽にするために約束を検討する必要があります。 –

+0

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promiseを参照してください。 –

答えて

0

まあ、私はマーティンホーネンに答えを与えたかったのですが、彼は利用できないようです。だから私は自分自身に答えるつもりです。しかしMartin Honnenは私の質問に答えました(コメントを見てください)。 Promisesはすばらしい解決策でしたが、もっと多くのコードを追加して状況をより複雑にする必要がなくても、その答えがより簡単になったと感じました。

答えは実際には非常に簡単でした。 load_band()関数をload_playlist()関数に直接追加することで、私の変数は望む順番で値を得ました。私は、呼び出されたすべての関数が、解析関数に渡された関数から呼び出されたことを確認しなければなりませんでした。私はコードを広範囲に書き直さなければならなかったが、それは価値があった。現在、私のload_prs()関数は中立関数として何度も使用することができます。値を取得し、その値に応じて、意図に応じて異なる関数を渡すことができます。今の例では、次のようになります。

function load_playlist(list) 
{ 
var px ; 
var plen = list.length ; 
for (px = 0 ; px < plen ; px++) 
    { 
    playlist_obj.band = get_val(list[px] , "band") ; 
    playlist_obj.album = get_val(list[px] , "album") ; 
    playlist_obj.title = get_val(list[px] , "title") ; 
    playlist.push(playlist_obj) ; 
    } 
load_band() ; 
} 

function load_band() { var t = playlist[0].band ; } 
load_prs(load_playlist , "nd/playlist" , "playlist") ; 

注:私は動作するように、この例を得たとき、私は私のplaylist配列はすべて同一であったオブジェクトを持っていたことを発見しました。これは、名前の値のペアを持つグローバルオブジェクトを使用していて、異なる時間に異なる値を与えるためです。

var playlist_obj = { band: "" , album: "" , title: "" } 

オブジェクトコンストラクタを使用してこれを解決できました。

// Object constructor 
function pobj(b , a , t) 
{ 
this.band = b ; 
this.album = a ; 
this.title = t ; 
} 

// Create local variables 
var band = get_val(list[px] , "band") ; 
var album = get_val(list[px] , "album") ; 
var title = get_val(list[px] , "title") ; 

// The new keyword creates a new object 
playlist_obj = new pobj(band , album , title) ; 

// Store the new object in the global array 
playlist.push(playlist_obj) ;