【问题标题】:Do running script tags block other script tags from downloading?运行脚本标签会阻止其他脚本标签下载吗?
【发布时间】:2012-05-27 17:24:47
【问题描述】:

这是来自HTML5 Boilerplate 中的index.html,就在</body> 标记之前:

<!-- JavaScript at the bottom for fast page loading: http://developer.yahoo.com/performance/rules.html#js_bottom -->

<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.7.2.min.js"><\/script>')</script>

<!-- scripts concatenated and minified via build script -->
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<!-- end scripts -->

<!-- Asynchronous Google Analytics snippet. Change UA-XXXXX-X to be your site's ID.
     mathiasbynens.be/notes/async-analytics-snippet -->
<script>
  var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
  (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
  g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
  s.parentNode.insertBefore(g,s)}(document,'script'));
</script>

我知道脚本标签会阻止并行下载,这就是为什么it's recommended to put them at the bottom

我的问题:浏览器是否真的要等到 jQuery 完全下载并执行后才开始下载plugins.js,然后是script.js

还是提前开始并尽快(并行)下载所有脚本,然后延迟每个脚本的执行直到前一个脚本完成执行完毕?

【问题讨论】:

    标签: javascript html optimization script-tag


    【解决方案1】:

    我的问题:浏览器真的等待 jQuery 完全下载并执行,然后才开始下载 plugins.jsscript.js

    可能会也可能不会,但可能不会;浏览器尝试(在限制范围内)并行下载以加快页面加载速度。

    还是提前开始并尽快(并行)开始下载所有脚本,然后将每个脚本的执行延迟到前一个脚本完成执行?

    对,因为那部分是required by the specification(没有asyncdefer 属性)。正如您的示例所示,在脚本运行之前,它甚至不一定确定脚本应该运行的顺序,因为脚本可能会插入另一个脚本。但它可以下载它们并准备好它们。

    【讨论】:

    • 这是否意味着 JavaScript 的异步加载技术等最佳实践在当今较新的浏览器中不那么重要了?他们是否只记得并行下载后外部脚本链接出现在文档中以执行它们的顺序?似乎是这样,因为如果我查看 chrome 开发人员工具/资源面板,大量的 js 文件会同时开始下载,并且不会像书籍中的屏幕截图(例如“更快的网站”)那样被阻止作为示例显示.
    • @malthoff:“他们是否只记得文档中外部脚本链接出现的顺序,以便在并行下载后执行它们?” 正确。如果你有(比如说)五个脚本,但加载其中两个的顺序并不重要,你可以标记那些async,在这种情况下(在现代浏览器上)它们会被评估重新完成下载,无论顺序如何。
    • "但它可以下载它们并准备好它们。"但实际上,浏览器会这样做吗?
    • @callum:哦,是的。只要有内容可以抓取,浏览器就会竭尽全力让 HTTP 线程保持忙碌状态。这一切都是为了首先展示完成的页面。
    【解决方案2】:

    HTML5 规范说:

    如果两个属性都没有[即async and defer] 存在,然后获取脚本并 在用户代理继续解析之前立即执行 页面。

    如果页面没有被解析,那么用户代理就无法知道哪些后续资源需要获取,因此严格遵守的浏览器在第一个资源实际执行之前应该无法获取更多资源。

    要了解为什么这样做有意义,请想象第一个脚本包含

    document.write("<!--"); 
    

    如果没有匹配的注释闭包,那么标记中脚本后面的所有内容都将成为注释的一部分,直到遇到下一个--&gt;。这可能会导致一个或多个资源引用被跳过。

    【讨论】:

      【解决方案3】:

      我发现这个细节更适合这个问题的答案,从http://www.html5rocks.com/en/tutorials/speed/script-loading/复制下面的内容参考它以获取更多细节。

      啊,幸福的简单。在这里,浏览器将并行下载这两个脚本并尽快执行它们,保持它们的顺序。 “2.js”在“1.js”执行完毕(或未能执行)之前不会执行,“1.js”在之前的脚本或样式表执行之前不会执行,等等。

      不幸的是,当这一切发生时,浏览器会阻止页面的进一步渲染。这是由于“网络第一时代”的 DOM API 允许将字符串附加到解析器正在处理的内容上,例如 document.write。较新的浏览器将继续在后台扫描或解析文档并触发下载它可能需要的外部内容(js、图像、css 等),但仍会阻止呈现。

      这就是为什么性能界的优秀人士建议将脚本元素放在文档的末尾,因为它会尽可能少地阻止内容。不幸的是,这意味着您的脚本在下载所有 HTML 之前不会被浏览器看到,并且此时它开始下载其他内容,例如 CSS、图像和 iframe。现代浏览器足够智能,可以优先考虑 JavaScript 而非图像,但我们可以做得更好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-29
        • 2018-10-05
        • 1970-01-01
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多