简体   繁体   English

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

[英]Async-loaded scripts with DOMContentLoaded or load event handlers not being called?

I've got a script with a DOMContentLoaded event handler—我有一个带有DOMContentLoaded事件处理程序的脚本——

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

Which I'm loading asynchronously—我正在异步加载——

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

However, the event handler is never called .但是,事件处理程序永远不会被调用 If I load it synchronously—如果我同步加载——

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

It works fine.它工作正常。

(Even if I change the DOMContentLoaded event to a load event, it's never called.) (即使我将DOMContentLoaded事件更改为load事件,它也永远不会被调用。)

What gives?是什么赋予了? The event handler should be registered irrespective of how the script is loaded by the browser, no?无论浏览器如何加载脚本,都应该注册事件处理程序,不是吗?

Edit : It doesn't work on Chrome 18.0.1025.11 beta but, with DOMContentLoaded , it does on Firefox 11 beta (but with load it doesn't).编辑:它无法在Chrome工作18.0.1025.11测试阶段,但与DOMContentLoaded在Firefox 11 Beta版(但load事实并非如此)。 Go figure.去搞清楚。

OH GREAT LORDS OF JAVASCRIPT AND THE DOM, PRAY SHOW THE ERROR OF MY WAYS!哦伟大的 JAVASCRIPT 和 DOM 领主,请指出我的方式的错误!

By loading the script asynchronously, you are telling the browser that it can load that script independently of the other parts of the page.通过异步加载脚本,您告诉浏览器它可以独立于页面的其他部分加载该脚本。 That means that the page may finish loading and may fire DOMContentLoaded BEFORE your script is loaded and before it registers for the event.这意味着页面可能会完成加载,并且可能会在加载脚本之前和注册事件之前触发DOMContentLoaded If that happens, you will miss the event (it's already happened when you register for it).如果发生这种情况,您将错过该活动(注册时已经发生了)。

In all modern browsers, you can test the document to see if it's already loaded ( MDN doc ), you can check:在所有现代浏览器中,您可以测试文档以查看它是否已加载( MDN doc ),您可以检查:

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

to see if the document is already loaded.查看文档是否已加载。 If it is, just do your business.如果是,就做你的事。 If it's not, then install your event listener.如果不是,则安装您的事件侦听器。

In fact, as a reference source and implementation idea, jQuery does this very same thing with it's .ready() method and it looks widely supported.事实上,作为参考源和实现思想,jQuery 用它的.ready()方法做了同样的事情,它看起来得到了广泛的支持。 jQuery has this code when .ready() is called that first checks to see if the document is already loaded..ready()被调用时,jQuery 有这个代码,它首先检查文档是否已经加载。 If so, it calls the ready function immediately rather than binding the event listener:如果是这样,它会立即调用就绪函数而不是绑定事件侦听器:

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

This is not the final answer but made me understand why is not correct using async with a script that need to modify DOM, so must wait to DOMContentLoaded event.这不是最终答案,但让我明白为什么将异步与需要修改 DOM 的脚本一起使用是不正确的,因此必须等待 DOMContentLoaded 事件。 Hope could be beneficial.希望可能是有益的。

在此处输入图片说明

(Source: Running Your Code at the Right Time from kirupa.com ) (来源: 在正确的时间运行您的代码来自 kirupa.com

Most vanilla JS Ready functions do NOT consider the scenario where the DOMContentLoaded handler is initiated after the document already has loaded - Which means the function will never run .大多数 vanilla JS Ready 函数不考虑在文档已经加载之后启动DOMContentLoaded处理程序的情况——这意味着该函数将永远不会运行 This can happen if you use DOMContentLoaded within an async external script ( <script async src="file.js"></script> ).如果您在async外部脚本 ( <script async src="file.js"></script> ) 中使用DOMContentLoaded ,则可能会发生这种情况。

The code below checks for DOMContentLoaded only if the document's readyState isn't already interactive or complete .下面的代码仅在文档的readyState尚未interactivecomplete检查DOMContentLoaded

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

If you want to support IE aswell:如果您还想支持 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!
});

One way around this is to use the load event on the window object.解决此问题的一种方法是在 window 对象上使用 load 事件。

This will happen later than DOMContentLoaded, but at least you don't have to worry about missing the event.这会晚于 DOMContentLoaded 发生,但至少您不必担心错过该事件。

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

If you really need to catch DOMContentLoaded event you can do use Promise object.如果你真的需要捕捉 DOMContentLoaded 事件,你可以使用 Promise 对象。 Promise will get resolved even if it happened earlier: 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");
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当evr DOMContentLoaded 事件触发时,函数restClient(url) 如何不被调用? - How the function restClient(url) is not being called whenevr DOMContentLoaded event fires? 防止在单击事件中重复调用异步加载功能 - Preventing a async load function from being called repetitively in a click event 延迟脚本是否在 DOMContentLoaded 事件之前执行? - Are deferred scripts executed before DOMContentLoaded event? 在完全加载 DOM 内容之前渲染 VueJS 事件处理程序? - VueJS event handlers being rendered before DOM content is completely loaded? DOMContentLoaded 事件为单个页面加载触发两次 - DOMContentLoaded event firing twice for a single page load 预加载器应该在 DOMContentLoaded 或加载事件中 - should preloader be inside DOMContentLoaded or load event 刷新后未调用文档加载事件 - Document load event not being called after refresh 在加载的脚本中,在.ready回调之前调用JQuery .load回调,初始化加载的脚本的正确方法是什么? - JQuery .load callback is called before .ready callback in loaded script, what is proper way of initialization loaded scripts? IE 9中未调用事件处理程序 - Event Handlers not being invoked in IE 9 JavaScript 中的事件处理程序是否按顺序调用? - Are event handlers in JavaScript called in order?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM