【问题标题】:Is DOMContentLoaded event EXACTLY the same as jQuery's .ready() function?DOMContentLoaded 事件是否与 jQuery 的 .ready() 函数完全相同?
【发布时间】:2012-07-16 10:12:19
【问题描述】:

我已经用 jQuery 的 $(document).bind('ready', function() {}); 替换了 window.addEventListener('DOMContentLoaded', function() {});,因为第一个无法在 IE .attachEvent(),如果我可以让 jQuery 很好地覆盖这个自己。

更换后不久,我注意到DOMContentLoaded 事件总是在页面加载/刷新后大约 0-2 毫秒被触发(至少这是我的日志脚本记录的),而.ready() 总是需要至少 15 -20 毫秒,在页面刷新后被触发(再次 - 由脚本记录)。

我纯粹是为了满足我的好奇心,为什么会有如此“显着”的延迟?当然,对我来说没有问题,jQuery 稍后会触发该事件。只是,因为我想知道所有的答案(并统治世界!:]),我睡不着! :]

编辑:在.ready() function doc 一些用户(尼克(Nexxar))指出:“jQuery 模拟 IE 上不存在的“DOMContentLoaded”事件,但使用的机制会触发比其他浏览器上使用的事件要晚得多”。也许这是一样的,我在问?

【问题讨论】:

    标签: javascript jquery dom events dom-events


    【解决方案1】:

    假设浏览器支持该事件:

    1. 真实事件可以支持任意document。 jQuery 将只使用它被加载的 document,无论你传递给它什么。
    2. 即使事件已经发生,jQuery 也会异步触发事件。如果事件已经发生,则附加 'DOMContentLoaded' 事件将不起作用。

    这些浏览器没有延迟,请参阅http://jsfiddle.net/rqTAX/3/(记录的偏移量以毫秒为单位)。

    对于不支持该事件的浏览器,jQuery 显然也适用于它们。它将使用与真正的DOMContentLoaded 不同的hacky 机制,并且不一定会像真正的DOMContentLoaded 那样立即触发:

    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( jQuery.isReady ) {
            return;
        }
    
        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }
    
        // and execute any waiting functions
        jQuery.ready();
    }
    

    【讨论】:

    • 如果我没有误解你的意思,你的回答只是解释了为什么在不支持DOMContentLoaded 的浏览器中可能会有延迟(时间改变,事件被触发)(比如IE
    • @trejder 抱歉,我没有看到任何类似的东西。见jsfiddle.net/rqTAX/3。差异就像 5-20 毫秒。在 chrome 和 firefox 中
    • 无需抱歉! :] 这纯粹是我的好奇心。也许我错过了什么。我想,我们可以关闭这个话题,至于我。谢谢!
    • @trejder 好吧,您至少可以接受我的回答,因为它提供了大多数人不知道的 2 个顶部差异;) 顺便说一句,您应该使用 $(document).ready 而不是 .bind,他们非常不同。
    • 感谢您的提醒,因为我是sure,我确实接受了您的回答! :] 对不起! BTW:为什么$(document).bind('ready', function() {});$(document).ready(function() {}); 如此不同?
    【解决方案2】:

    jQuery通过绑定documentreadystatechange事件来模拟这个事件,这是在oldIE中模拟DOMContentLoaded的标准方式。

    According to the jQuery source,该事件“延迟”触发,但在window.onload 之前触发。但是,我找不到该事件准确触发的 whenDOMContentLoaded 在 DOM 构建完成并准备好编写脚本时触发,所以 readystatechange 在之后触发;也许它等待布局渲染或类似的样式,或者在渲染/布局过程中稍后触发事件?

    无论如何,它可能会在DOMContentLoaded 之后触发,这可能是因为 IE 决定将documentreadyState 更新为“完成”。

    (如果有人有明确的答案,请发表评论,我会更新这个答案;我很想知道它什么时候会触发自己,但我在任何文档或任何网站上都找不到该答案会期望像 Quirksmode。)

    【讨论】:

    • 好的,但与上面类似。你主要是在谈论IE。最新的 Chrome 和最新的 Firefox 也会出现同样的延迟。
    • DOMContentLoaded 发生在脚本(常规和defered)运行之后(async 除外)
    【解决方案3】:

    'ready' 似乎稍后触发的另一个原因(在实践中)是可能有许多事件与它相关联。如果其中任何一个是长时间运行的同步操作,那么就绪事件将在很久以后出现。例如我使用了 knockout.js,它可能需要 500 毫秒来初始化页面。


    但是,使用您的最小测试页面当然不是这样。我尝试运行以下命令:

     console.log(window.performance.timing.domContentLoadedEventEnd -
                 window.performance.timing.domContentLoadedEventStart);
    

    即使对于您的简单超级页面,这也提供大约 6 毫秒


    我还拿了你的代码并通过 Chrome 的性能工具运行它,发现了一些有趣的东西:

    • 顺便说一句:垂直的蓝色条是 DOMCONTENTLOADED,绿色是“第一次绘制”
    • 您可以看到,即使是对 DOMCONTENTLOADED 事件的超级简单函数调用也可能需要 5 毫秒(这是在 i7 上)。请记住,它需要被解析并且需要初始化。
    • 回调以青色(匿名)显示,第一个来自 DOMCONTENTLOADED 事件,第二个来自“就绪”回调。
    • 您会注意到“Timer Fired”(即setTimeout)。所以它无论如何都不是瞬时的。

    看看jQuery source code,你会发现他们实际上为回调设置了一个计时器:

    // Handle it asynchronously to allow scripts the opportunity to delay ready
    window.setTimeout( jQuery.ready );
    

    我不完全确定他们在这里的意思(任何想法) - 但它解释了行为。我可以看到它有助于避免竞争条件,并且阻止 UI 但我不清楚“延迟准备好”。

    【讨论】:

    • setTimeout() 是 IE9-10 在为其添加侦听器之前触发 DOMContentLoaded 事件的解决方法。代码检查document.readyState 是否已经完成,然后添加setTimeout() 以将jQuery.ready 回调推送到事件队列,从而在jQuery.ready 执行之前为其他排队的异步回调提供执行机会。
    • 但我使用的是 Chrome!时间可能可以忽略不计,但我正在尝试启动 SignalR 连接并需要尽快完成
    • Chrome 会正确处理它,它不会触发 DOMContentLoaded 事件,直到它到达 </body> 标记的末尾。 IE9-10 没有,所以它需要一个解决方法。 jQuery 代码在 if 语句中对此进行检查。如果 document.readyState 没有准备好,它会退回到正确的行为。
    • 是的,它工作,但由于计时器的原因,存在不必要的延迟。也许存在某种竞争条件,但我发现将 SignalR 初始化代码放入我自己的 DOMContentLoaded 中更快,因为我只需要支持现代浏览器
    • 这可能是由于 jQuery 本身解析的原因,即 84KB。
    【解决方案4】:

    除了我之外还有人使用 jQuery 吗? ;)

    jQuery 3.0 开始,仅推荐使用 $( handler ) 语法,
    (相当于$( document ).ready( handler ))。

    来自 API 文档:.ready()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      相关资源
      最近更新 更多