使用 async 和 defer 按顺序加载脚本

Using async and defer to load scripts in order

提问人:Johny P. 提问时间:10/27/2017 最后编辑:Heretic MonkeyJohny P. 更新时间:9/29/2020 访问量:3812

问:

因此,我正在遵循 Google PageSpeed 的建议来推迟首屏脚本。假设这是我的代码:<head>

<script src="/js/jquery.js"></script>
<script src="/js/functions.js"></script>

该脚本依赖于 jQuery,因此在 之前加载和执行至关重要。functions.jsjquery.jsfunctions.js

我尝试过:

推迟

<script src="/js/jquery.js" defer></script>
<script src="/js/functions.js" defer></script>

虽然这可以正常工作并正确执行,但当我加载页面时,我看到它闪烁,就好像 CSS 尚未加载一样。请注意,上面的代码位于 .如果我从中删除该属性,闪烁就会消失。这就引出了我的问题:functions.js<head>deferjquery.js

混合

<script src="/js/jquery.js" async></script>
<script src="/js/functions.js" defer></script>

在依赖脚本和依赖脚本上使用是否确保它们始终按该顺序执行?它似乎在我的测试中有效,但我对解析器的工作原理了解不够,无法确定。asyncdefer

JavaScript jQuery 异步 HTML 解析

评论


答:

0赞 Zalaboza 11/26/2017 #1

是的,在 chrome 上,有时在 Firefox 上。.

规范说它们将按顺序加载,但加载意味着下载不执行,因此如果文件在其他文件之前完成下载,它将首先运行,因此我不建议您使用 defer 或 async 属性依赖执行顺序

3赞 Flimm 11/13/2018 #2

答案是,如果您使用 或 ,您将失去对执行脚本的顺序的保证。asyncdefer

async脚本是异步执行的,不能保证有哪个顺序。 脚本在文档解析后执行,但不能保证它们是否会按顺序执行。(具体看一下这个关于延迟脚本的问题defer

不幸的是,在您的情况下,您必须通过删除 and 属性来同步运行。jquery.jsdeferasync

展望未来,当我们转向模块时,指定依赖项并及时(并且仅加载一次)将变得更加容易。

评论

0赞 Johny P. 11/13/2018
我还没有研究过模块。也许在我的下一个项目中,我会检查 ECMAScript 标准是怎么说的。
1赞 CertainPerformance 2/28/2019
如果不想,则无需使用同步脚本进行阻塞 - 使用 or 加载脚本,侦听其事件,一旦触发,就创建另一个依赖于前一个脚本的脚本,依此类推。asyncdeferload<script>
2赞 cquezel 12/15/2018 #3

虽然我不确定当前的浏览器是如何实现该标准的,但对脚本(没有 type=“module”的经典脚本元素)和模块(带有 type=module 的脚本元素)的执行顺序有最低限度的保证。

1) 未指定 defer 或 async 的经典脚本将按照它们在 html 文档中出现的顺序执行(在解析文档时)。它们在延迟的经典脚本和非异步模块之前执行。

2) 延迟的经典脚本和非异步模块按照它们在 HTML 文档中出现的顺序执行(在文档解析后)。

请参阅此处有关处理模型的第 20 点:https://www.w3.org/TR/html5/semantics-scripting.html#script-processing-model