异步和文档就绪

Posted

技术标签:

【中文标题】异步和文档就绪【英文标题】:Async and document ready 【发布时间】:2012-06-18 02:37:33 【问题描述】:

我尝试通过在我的脚本中添加一些async 属性来优化我的页面。它似乎破坏了我的 javascript,因为 $(document).ready 在所有脚本加载之前执行!

我看到我可以通过输入$(window).load 而不是$(document).ready 来解决我的问题,但我想知道是否有更好的解决方案。 这个解决方案在我的案例中引发了 2 个问题:

    我必须更改所有 $(document).ready 并告诉所有开发人员不要再使用它了 脚本将在所有图像加载后执行。我的网站有很多沉重的图片,我真的需要在 dom 准备好后尽快执行一些脚本。

你有一些魔术吗?也许将所有脚本放在最后?使用defer 而不是async

【问题讨论】:

在 jQuery 检测到文档就绪状态后,还会为使用 document.ready 的脚本执行文档就绪调用。在使用 jQuery 的网站上,在加载完所有资源后尝试使用以下内容:$(document).ready(function () console.log('READY');); 【参考方案1】:

经过一些广泛的研究,我可以肯定地说,将脚本放在页面末尾是最佳实践。

雅虎同意我的观点:http://developer.yahoo.com/performance/rules.html#js_bottom

Google 不谈论这种做法,似乎更喜欢异步脚本:https://developers.google.com/speed/docs/best-practices/rtt#PreferAsyncResources

恕我直言,将脚本放在页面末尾比异步/延迟有几个好处:

它适用于所有浏览器(是的,甚至 IE ;)) 您保证执行顺序 您不需要使用$(document).ready$(window).load 您的脚本可以在图像加载之前执行 作为异步/延迟,您的页面将显示得更快 当 DOM 触发 ready 事件时,所有脚本都被加载 可以通过将所有 js 合并到一个文件中来优化(通过 mod_pagespeed 之类的工具)

我能看到的唯一缺点是浏览器无法并行下载。 使用 async/defer 的一个很好的理由是当您有一个完全独立的脚本(不需要依赖执行顺序)并且不需要在特定时间执行时。示例:谷歌分析。

【讨论】:

它并不能通过将它们放在 DOM 中来完全保证执行。如果你的浏览器有太多的 JavaScript 和/或 HTML,你需要 requirejs 或任何其他类似的系统加载器。我看到了只适用于压缩 JavaScript 的设计,因为它太多了。这是一个引导 3.x 响应式主题,在向下滚动页面时会产生效果。 唯一一个在 2012 年不使用 defer 的有价值的论点是,正如 Yahoo 所说:Firefox 不支持 DEFER 属性。但是现在在 2020 年,您可以在任何地方使用延迟模式:caniuse.com/#feat=script-defer【参考方案2】:

defer 在这里肯定会有所帮助。

defer 通常比async 好,因为它:

异步加载(就像async) 保证执行顺序(不同于async) 在最后执行(不像async 在页面仍在加载时并行执行,它实际上停止 dom 解析!) jquery ready 触发 “延迟”脚本已加载(这就是您的要求)

This SO answer 有一张很好的图片说明了延迟/异步加载顺序,超级好理解。

【讨论】:

【参考方案3】:

如果您不想使用脚本加载器,您可以使用以下方法,这样您就可以将 $(document).ready 脚本留在原处 - 修改如下:

$(()=>

    function checkAllDownloads() 
        // Ensure your namespace exists.
        window.mynamespace = window.mynamespace || ;

        // Have each of your scripts setup a variable in your namespace when the download has completed.
        // That way you can set async on all your scripts except jquery.
        // Use the document ready event - this code - to check if all your scripts have downloaded.
        if (window.mynamespace.script1 && window.mynamespace.script2)

          // Proceed with page initialisation now that all scripts have been downloaded.
          // [ Add your page initialisation code here ].
          return;
         
        // Not all downloads have completed.
        // Schedule another check to give the async downloads time to complete.
        setTimeout(checkAllDownloads, 500);
    

    // check if it is safe to initialise the page by checking if all downloads have completed.
    checkAllDownloads();

    )

【讨论】:

以上是关于异步和文档就绪的主要内容,如果未能解决你的问题,请参考以下文章

阻塞,非阻塞, 同步,异步

同步/异步 异步回调 协成 线程队列

如何从 Angular 中的异步输入中获取“就绪”值

同步异步阻塞和非阻塞

同步异步阻塞非阻塞

text Angular 2如何使子组件等待异步数据准备就绪