一位读者最近写信给我(本质上)问我
当
script
已经在页面底部时,使用async
属性有什么理由吗?
我不是这方面的专家,但我的理解是……
他指的是这个
<script async src="/js/script.js"></script>
</body>
我们之前已经 讨论过这个问题。 现在重新审视这个问题尤其有趣,因为 async
属性 现在确实是 执行异步脚本的唯一推荐方式。
那么,当 script
已经在页面底部时,使用 async
属性有什么理由吗?
简短回答
没有。
更详细的回答
您试图用 async
属性来阻止解析器阻塞。 如果您使用 async
属性,您就是在说:我不希望浏览器在下载此脚本时停止它正在做的事情。 我知道这个脚本在运行时并不真正依赖于 DOM 中的任何内容已准备就绪,并且它也不需要按任何特定顺序运行。
如果您在页面底部加载脚本,解析器实际上已经完成了,因此阻塞它并不重要。 您实际上已经在 延迟 脚本,这有点像更强硬的异步。 参见比较。
它甚至可能有点危险。
如果您只是在假设异步 = 好,那么您可能会做类似的事情
<script async src="/js/libs.js"></script>
<script async src="/js/page.js"></script>
</body>
这可能是个坏消息,因为“libs.js”很可能对“page.js”有依赖关系,但现在无法保证它们的运行顺序(不好)。
这主要是一个第三方问题。
第三方脚本是异步脚本的主要用例。 他们(第三方)无法控制您在页面上放置该脚本的位置,因此它们通常被设计为无论何时/何地加载都可以工作。 您也无法控制第三方(这就是第三方,韦恩),因此确保它们不会减慢您的网站速度是理想的。
还有其他用例吗?
我想,如果你真的想立即开始下载你自己的脚本之一,并且不在乎它何时运行,你可以把它放在 <head>
中并使其异步。
我可能有点错了。
我倾向于搞砸这些 JavaScript 建议文章,所以如果我做错了,让我们在评论中讨论一下,我会确保这篇文章的内容反映最新的信息。
仍然有一个使用 async 的用例,即使它被放在底部。 任何在文档中同步添加的脚本都会阻塞 domcontentloaded(ready)事件,该事件通常用于初始化 UI 小部件/组件。
但你绝对是对的。 现在 async 最重要的用例是第三方代码,它必须异步加载,或者最好使用友好的 iframe 技术。 不幸的是,这通常是不可能的,因为脚本编写不当。
我喜欢简短的回答,它更简洁。
+10
根据作者在 igvita.com 上链接的文章中的评论,仍然存在一个好处
感谢你的这篇文章,否则我不会学到关于 async 的这些细节!
参见:https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/#comment-1398899164
这意味着预加载器无法找到没有 async 属性的脚本吗? 这似乎很奇怪。 只是在想,我需要深入了解那个对话才能了解更多信息。
@ Chris Coyier:两者都可以被预加载扫描器发现。 但是,如果您有(例如)两个相互独立的脚本,使用 async 标志标记每个脚本可以让浏览器以任何顺序运行它们,因此,如果(例如)第一个脚本下载速度很慢,浏览器可以自由地在第一个脚本完成下载并运行之前运行第二个脚本。 如果您省略 async,第二个脚本仍然必须等待第一个脚本。 所以它仍然有用的用途,即使脚本位于 HTML 的末尾。
@ChrisCoyier @Chris 引用是关于使用 async 属性与使用脚本注入。 它没有讨论在 script 标签上是否使用 async 属性。
我对 async 属性的理解,@T.J.Crowder 做了很好的总结。 如果你知道自己在做什么,async 属性是有益的,但它不是底部加载的 script 标签的良好默认值,正如 Chris 在这篇文章中得出的结论。
虽然我同意你不应该使用它,因为它不能保证执行顺序…… 通过使用 async 属性,它实际上会像正常脚本标签一样执行两次脚本。 通过将脚本标签注入 dom,平均需要 0.1 秒才能完成,但我仍然认为这是最好的解决方案。
快两倍**。 Chris 上面的评论也是正确的。
当
script
已经在页面底部时,使用async
属性有什么理由吗?我说:不,但有时是!
当底部的
script
相互独立时,我们可以使用async
,这样加载第一个脚本的延迟就不会影响第二个脚本。另外一个问题。 如果您要加载,比如,页面底部的 10 个脚本,并且它们之间没有依赖关系,那么将它们全部异步加载是否可以帮助它们更快地加载,所有脚本并行加载,而不是可能 6 个请求然后是另外 4 个请求?
我有一个死忠的后台开发人员朋友,他坚称将脚本放在页面底部是一种不好的做法,并且当他在页面中搜索脚本时,发现它们在底部,他就会非常生气。 将它们放在 body 结束之前是否真的更可取,还是主要是一个便利问题?
他是否有任何理由证明 为什么 这样做是一种不好的做法——除了“他只是觉得很烦”,因为找到它们需要花点时间……?
如果有人想深入研究,这是我关于 JS 加载的首选文章,过去我发现它非常有用。
http://www.html5rocks.com/en/tutorials/speed/script-loading/
josh
这不是为了方便,而是为了性能。在 body 之前添加脚本会增加渲染时间。除了某些例外,一些分析脚本更喜欢开发者将脚本放在头部,以便在页面被调用时立即跟踪它。
如何只使用 async 并使用一个合并后的脚本,而不是将它们全部拆开,担心执行顺序并可能浪费 http 请求?在命令行上运行
cat *.js > app.min.js
可以将所有 JS 文件合并。我认为合并是另一个问题。它很重要。从本文的角度来看,应该假设您已经进行了尽可能多的智能合并。仅仅因为一个页面加载了两个脚本并不意味着他们没有进行合并。使用一个在所有页面上加载的
global.js
(从而利用缓存)和一个只在某些页面上加载的subpage.js
可能是合理的,但它依赖于全局中的内容。@ Chris Coyier: 没错。或者您已经做出了商业决策,从免费 CDN 下载标准内容,而将自己的内容保存在本地(并处理这些内容以混乱顺序出现的情况)。
这些都不是教条。它们是明智的、务实的选择。
或者至少,您知道,这就是我们努力的目标…… ;-)
如何像这样异步加载脚本?
嗯,我想插入 HTML 代码…
<script src=”/js/AsyncLoader.js”></script>
<script>
AsyncLoader.Ready(function () {
AsyncLoader.Load([“jQuery”, “extensions”], function () {
// 应用程序代码在此。
});
});
</script>
http://www.dustindiaz.com/scriptjs
带有依赖项管理的异步加载 KAPOW。
依赖项属性会更好,但由于它不存在,因此这非常有用。
感谢您的澄清。最近我在项目中遇到了 async 问题。我更喜欢在页脚加载脚本。但是,将脚本放在页面底部有什么缺点吗?即使只有一个?