我认为,杰克·阿奇博尔德(Jake Archibald)早在2013年就向我们提供了一些见解,这些见解可能会对该主题产生更大的积极性:
https://www.html5rocks.com/zh-CN/tutorials/speed/script-loading/
圣杯正在立即下载一组脚本,而不会阻止渲染,并按添加顺序尽快执行。不幸的是,HTML讨厌您,并且不允许您这样做。
(...)
答案实际上是在HTML5规范中,尽管它隐藏在脚本加载部分的底部。“ 异步IDL属性控制元素是否将异步执行。如果设置了元素的“ force-async”标志,则异步IDL属性在获取时必须返回true,在设置时必须返回“ force-async”必须首先取消设置标志... ”。
(...)
动态创建并添加到文档中的脚本默认情况下是异步的,它们不会阻止渲染并在下载后立即执行,这意味着它们可能以错误的顺序出现。但是,我们可以将它们明确标记为不异步:
[
'//other-domain.com/1.js',
'2.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
这使我们的脚本混合了普通HTML无法实现的行为。通过显式不异步,脚本被添加到执行队列中,与我们在第一个纯HTML示例中添加的脚本相同。但是,通过动态创建它们,它们可以在文档解析之外执行,因此在下载它们时不会阻止渲染(不要将非异步脚本加载与sync XHR混淆,这从来都不是一件好事)。
上面的脚本应内联包含在页面的开头,应尽快对脚本下载进行排队,而不会破坏渐进式渲染,并应按指定的顺序尽快执行。“ 2.js”可在“ 1.js”之前免费下载,但要等到“ 1.js”成功下载并执行或无法执行后才能执行。欢呼!异步下载但命令执行!
不过,这可能不是加载脚本的最快方法:
(...)在上面的示例中,浏览器必须解析并执行脚本以发现要下载的脚本。这会将脚本隐藏在预加载扫描仪中。浏览器使用这些扫描仪在您可能下一步访问的页面上发现资源,或者在解析器被其他资源阻止时发现页面资源。
我们可以通过将其添加到文档的开头来重新添加可发现性:
<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">
这告诉浏览器页面需要1.js和2.js。link [rel = subresource]与link [rel = prefetch]类似,但语义不同。不幸的是,Chrome目前仅支持该脚本,您必须声明要加载两次的脚本,一次是通过链接元素,一次是在脚本中。
更正:我最初说这些是由预加载扫描仪拾取的,不是,而是由常规解析器拾取的。但是,预加载扫描程序可能无法进行预加载,而可执行代码中包含的脚本则永远无法预加载。感谢Yoav Weiss在评论中纠正了我。
async
是新的(ish),但defer
自IE4以来已成为IE的一部分。defer
是最近才被添加到其他浏览器中的,但是这些浏览器的旧版本往往会少得多。