2017-02-13 35 views
-3

解決方案:人們似乎一直在我打電話給我的排隊機制成的window.onload的方式的問題。的JavaScript函數調用失敗的頭,但不是在身體

序言 - 我很高興看到我被標記爲重複,這裏的解決方案是使用在window.onload,這是我已經在使用的東西在這裏。一些評論指出了我從另一個stackoverflow解決方案中得到的隊列可能存在的問題,但由於缺乏闡述,使我處於黑暗中。

問題:如果我做的頭一個函數調用,它失敗。如果我在正文中進行函數調用,它會成功。爲什麼?

擴展:爲什麼在調用中global.js相同的功能,這是失敗的呼叫以上,成功嗎?

我有一些JavaScript創建各種各樣的onload事件「隊列」(在global.js功能addLoadEvent)。對這個函數的調用會在調用onload時添加到隊列中。

除此之外,我發現,如果它位於頭VS體內特定的腳本函數調用失敗。我無法弄清楚爲什麼,因爲所有需要的東西(其他js函數)都被加載到函數調用本身之上,直到onload纔會觸發對函數的實際調用,從而確保存在必要的html元素。裝載的

訂單:

  1. HTML文件多達頭
  2. global.js - 包括addLoadEvent(FUNC)
    • addLoadEvent X2(成功)
  3. 內嵌腳本頭 - 包括initialFighter()
    • addLoadEvent(位置的一個 - 失敗)頭
      • addLoadEvent(位置處的兩個 - 成功)後
    • HTML文件
  4. onload事件觸發排隊呼叫

爲目的這個問題,基於它的位置失敗或成功的函數調用如下。

addLoadEvent(initialFighter()); 

下面是剝離下來的HTML,注意標記了2個位置。如果我複製上面的函數調用粘貼到位置一,它會失敗。如果我將上面的函數調用粘貼到位置2,它會成功。

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8" /> 
    <script src="global.js"></script> 
    <script type="text/javascript"> 
    function showFighter(id) { 
    var pic = document.getElementById("picture"); 
    var picPath = 'url(images/' + id + '.png)'; 
    pic.style.backgroundImage = (picPath); 
    } 
    function initialFighter() { 
    var fighter = getURLParameter('fighter'); 
    if (typeof(fighter) != "undefined" && fighter != null) { 
     showFighter(fighter); 
    } else { 
     showFighter('Foobar'); 
    } 
    } 
    ***** LOCATION ONE ***** 
    </script> 
</head> 
<body> 
<header></header> 
<nav id="nav"></nav> 
<section id="fighters"> 
    <div id="picture"></div> 
    <div id="text"></div> 
    <script type="text/javascript"> 
    ***** LOCATION TWO ***** 
    </script> 
</section> 
<footer id="footer"></footer> 
</body> 
</html> 

下面是global.js,這是加載的第一個腳本文件:

注意,有2 addLoadEvent(FUNC)調用這裏,和他們成功(不運行,直到HTML元素後存在),儘管在其他方面都高於實際水平。

function addLoadEvent(func) { 
    var prevOnLoad = window.onload; 
    if (typeof window.onload != 'function') { 
    window.onload = func; 
    } else { 
    window.onload = function() { 
     if (prevOnLoad) { 
     prevOnLoad(); 
     } 
     func(); 
    } 
    } 
} 

function loadFile(id, filename) { 
    var xmlhttp; 
    if (window.XMLHttpRequest) { 
    xmlhttp=new XMLHttpRequest(); 
    } 
    xmlhttp.onreadystatechange=function() { 
    if (xmlhttp.readyState==4 && xmlhttp.status==200) { 
     document.getElementById(id).innerHTML=xmlhttp.responseText; 
    } 
    } 
    xmlhttp.open('GET', filename, true); 
    xmlhttp.send(); 
} 

addLoadEvent(loadFile('nav', 'nav.txt')); 
addLoadEvent(loadFile('footer', 'footer.txt')); 

function getURLParameter(name) { 
    return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null; 
} 
+1

'addLoadEvent(loadFile('nav','nav.txt'));'不會做你認爲它做的事。 – zzzzBov

+0

「addLoadEvent」的參數必須是函數,而不是函數的調用。 – Barmar

+0

你能否澄清這些評論?如果它沒有做我認爲正在做的事情,它在大多數地方仍然如此工作?巴納爾,你表示我發送了不正確的參數給addLoadEvent,但它在大多數情況下仍然有效?如果參數的類型錯誤,是不是會失敗100%? – Doug

回答

1

addLoadEvent的參數應該是一個函數,這將在onload回調過程中被調用。您正在立即調用函數,並傳遞它的返回值,所以函數不會等待onload事件,並且您會收到錯誤,因爲元素不在DOM中。它應該是:

addLoadEvent(function() { loadFile('nav', 'nav.txt'); }); 
addLoadEvent(function() { loadFile('footer', 'footer.txt'); }); 
addLoadEvent(initialFighter); 

你並不需要一個匿名的包裝功能initialFighter,因爲它不帶任何參數。你只需要忽略(),所以你傳遞了一個函數的引用,而不是立即調用函數。

此外,而不是通過保存舊的值,把它的新的函數內部鏈接onload事件處理程序,你可以簡單地使用addEventListener,因爲這些自動添加到偵聽器列表而不是替換它的:

function addLoadEvent(func) { 
    window.addEventListener("load", func); 
} 
+0

有趣。解釋是有道理的,我會嘗試實現它,但我仍然無法弄清楚如果這兩個loadFile調用如果沒有排隊,它們是如何工作的。如果不排隊,這些呼叫顯然是在它們應該修改的元素存在之前發生的,這本應該導致它們失敗呢?糟糕編輯,爲回答第2部分,我將不得不看看addEventListener,我不熟悉如何綁定到window.onload。 – Doug

+0

如果你把它放在位置2,'loadFile('nav','nav.txt')'應該可以工作,但是loadFile('footer','footer.txt')'應該失敗,因爲位置2位於加載'nav'元素。對'loadFile'的調用沒有排隊,它會立即發生。 – Barmar

+0

'initialFighter()'在body中起作用,因爲它是在'picture'元素被加載之後。 – Barmar