没有调用带有DOMContentLoaded或加载事件处理程序的异步加载脚本?

时间:2012-02-11 01:32:39

标签: javascript dom onload

我有一个带有DOMContentLoaded事件处理程序的脚本 -

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

我正异步加载 -

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

但是,永远不会调用事件处理程序 。如果我同步加载它 -

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

工作正常。

(即使我将DOMContentLoaded事件更改为load事件,也不会调用它。)

是什么给出的?无论浏览器如何加载脚本,都应该注册事件处理程序,不是吗?

修改:它不适用于Chrome 18.0.1025.11测试版,但是对于DOMContentLoaded,它在Firefox 11 beta上 (但使用{{ 1}}它没有)。去图。

OH伟大的JAVASCRIPT和DOM,祈祷显示我的方式的错误!

4 个答案:

答案 0 :(得分:55)

通过异步加载脚本,您告诉浏览器它可以独立于页面的其他部分加载该脚本。这意味着页面可能已完成加载,并且可能在加载脚本之前和注册事件之前触发DOMContentLoaded。如果发生这种情况,您将错过该事件(当您注册时已经发生了这一事件。)

在某些浏览器中,您可以测试文档以查看它是否已加载。我没有检查所有浏览器兼容性,但在Firefox 3.6+(MDN doc)中,您可以检查:

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

查看文档是否已加载。如果是,那就做你的事。如果不是,请安装您的事件监听器。

事实上,作为参考源和实现的想法,jQuery使用它的.ready()方法做了同样的事情,它看起来受到广泛支持。当调用.ready()时,jQuery有这个代码,它首先检查文档是否已经加载。如果是这样,它立即调用ready函数而不是绑定事件监听器:

// 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 );
}

答案 1 :(得分:23)

这不是最终的答案,但让我理解为什么使用异步与需要修改DOM的脚本不正确,所以必须等待DOMContentLoaded事件。希望可能是有益的。

enter image description here

(资料来源:Running Your Code at the Right Time from kirupa.com

答案 2 :(得分:3)

解决此问题的一种方法是在窗口对象上使用load事件。

这将比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");
});

答案 3 :(得分:2)

大多数vanilla JS Ready函数在文档已经加载后不考虑DOMContentLoaded处理程序设置的情况 - 这意味着该函数永远不会运行。如果您在DOMContentLoaded外部脚本(async)中查找<script async src="file.js"></script>,就会发生这种情况。

以下代码仅在文档的DOMContentLoaded尚未readyStateinteractive时才会检查complete

var DOMReady = function(callback) {
  document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback());
};
DOMReady(function() {
  //DOM ready!
});

如果你想支持IE以及:

var DOMReady = function(callback) {
    if (document.readyState === "interactive" || document.readyState === "complete") {
        callback();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback());
    } else if (document.attachEvent) {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading') {
                callback();
            }
        });
    }
};

DOMReady(function() {
  // DOM ready!
});