2017-08-14 29 views
0

我有一個外部XML文件,我想使用Javascript解析,但在另一個Javascript函數執行之前。我想將XML文件中的值存儲在全局對象中。問題是我解析我的XML異步,因爲同步解析已被棄用。 Javascript函數在解析XML之前執行,所以我得到一個錯誤,因爲全局變量是undefined在執行Javascript函數之前解析XML

我試着調用函數來解析一個Javascript文件中的XML文件,然後使用defer屬性在另一個文件中調用該函數。但是這確實有效,因爲解析器在所有腳本執行後仍然執行。我很難過!我也嘗試在Javascript函數上使用setTimeout()方法,但最後還會產生未定義的值。

我已經閱讀了關於堆棧溢出的幾個問題,這些問題與腳本的執行順序有關。我會說這個問題教會了我很多關於執行順序的事情。

注:還有更多我的劇本比這裏顯示,所以我剛纔添加的最基本的要素來說明我是如何解析我的XML文件,並且值存儲爲未定義。

更新:我已經用這種方式編寫了解析器,這樣我就可以以中立的方式使用了。解析器使用很多次,每次發生不同的事件都取決於使用情況。這就是爲什麼我沒有在onreadystatechange函數中添加特定功能。

我使用XML DOMXMLHttpRequest解析我的XML文件。

// 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> 

當我嘗試t時調用另一個訪問同一腳本中的全局對象的函數,我得到未定義的值。 var t返回undefined,因爲load_band()load_prs()之前執行。

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

另一件要指出的事情。一旦所有腳本完成執行,解析器就會工作並將值存儲在全局對象中。但是我需要它在'load_band'函數不被調用之前發生。當調用'load_band'函數時,我得到一個錯誤。 – Xavier

+1

好吧,你必須將'load_band()'移到onreadystatechange處理程序中的代碼中,分別從那裏調用代碼。總的來說,現在你應該看看Promises來緩解這樣的任務。 –

+0

請參閱https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise。 –

回答

0

那麼,我想給Martin Honnen一個答案,但是,他似乎無法使用。所以我要回答自己。但是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) ; 
相關問題