2012-02-11 128 views
22

我有一個DOMContentLoaded事件的腳本handler-未調用DOMContentLoaded或加載事件處理程序的異步加載腳本?

document.addEventListener('DOMContentLoaded', function() { 
    console.log('Hi'); 
}); 

我敢加載asynchronously-

<script async src=script.js></script> 

然而,事件處理程序從不叫。如果我同步加載它 -

<script src=script.js></script> 

它工作正常。

(即使我改變DOMContentLoaded事件爲load事件,它永遠不會被調用。)

是怎麼回事?無論腳本如何由瀏覽器加載,都應該註冊事件處理程序,不是嗎?

編輯:它無法在Chrome 18.0.1025.11測試工作,但與DOMContentLoaded,它確實在Firefox 11 Beta版(但load事實並非如此)。去搞清楚。

OH很棒的JAVASCRIPT和DOM,我的方式錯誤顯示錯誤!

+1

通過asynchrounously加載腳本,你告訴它可以獨立加載頁面的其他部分的該腳本的瀏覽器。這意味着頁面可能會完成加載,並可能在加載腳本之前和註冊事件之前觸發DOMContentLoaded。如果發生這種情況,您將錯過該事件(在您註冊時已發生)。 – jfriend00 2012-02-11 01:44:26

+0

Oh-interedasting。所以我真的應該測試已經解僱的事件 - (**編輯**:實際上,因爲我在腳本之後依賴事件觸發,所以它不應該是異步的)。涼。把它寫成一個答案,你可以有一個upvote :) – user1203233 2012-02-11 01:47:01

回答

46

通過異步加載腳本,您告訴瀏覽器它可以獨立於頁面的其他部分加載該腳本。這意味着頁面可能會完成加載並可能在加載腳本之前和註冊事件之前觸發DOMContentLoaded。如果發生這種情況,您將錯過該事件(在您註冊時已發生)。

在某些瀏覽器中,您可以測試文檔以查看它是否已加載。我沒有檢查所有的瀏覽器的兼容性,但在Firefox 3.6+(MDN doc),您可以檢查:

if (document.readyState !== "loading") 

,看看文件已加載。如果是,就做你的生意。如果不是,那麼安裝你的事件監聽器。

事實上,作爲一個參考源和實現思路,jQuery和它的.ready()方法完全相同,它看起來被廣泛支持。當調用.ready()時,jQuery具有此代碼,它首先檢查文檔是否已加載。如果是這樣,它調用現成的功能立即而不是綁定事件偵聽器:

// Catch cases where $(document).ready() is called after the 
// browser event has already occurred. 
if (document.readyState === "complete") { 
    // Handle it asynchronously to allow scripts the opportunity to delay ready 
    return setTimeout(jQuery.ready, 1); 
} 
+0

是的先生,這就是我需要知道的。我對upvote撒謊 - 沒有足夠的代表;)我希望有人能夠爲你投票贊成這個:) – user1203233 2012-02-11 01:55:55

+0

如果'document.readyState'只是壁虎:繞過它的方式是運行另一個'DOMContentLoaded'事件處理程序*同步*這將在運行時設置一個全局標誌,我們可以在以後檢查:) **編輯**:哦等待所有的酷瀏覽器支持它,所以我們罰款 – user1203233 2012-02-11 01:59:48

+7

嘗試的事情,結果檢查'document.readyState =='complete''是不夠的* - 當檢查發生時,'document.readyState'是'interactive'。檢查'document.readyState!='loading''雖然工作正常:) – user1203233 2012-02-11 14:35:34

2

的一種方法是在窗口對象上使用加載事件。

這將比DOMContentLoaded晚,但至少您不必擔心丟失事件。

window.addEventListener("load", function() { 
    console.log('window loaded'); 
}); 

如果您確實需要捕獲DOMContentLoaded事件,則可以使用Promise對象。承諾將得到解決,即使它早些時候發生的事情:

HTMLDocument.prototype.ready = new Promise(function (resolve) { 
if (document.readyState != "loading") 
    return resolve(); 
else 
    document.addEventListener("DOMContentLoaded", function() { 
     return resolve(); 
    }); 
}); 

document.ready.then(function() { 
    console.log("document ready"); 
});