我想使用
defer
和 async
加载以下 JavaScript 代码:
<script defer async src="/js/somescript.js"></script>
由于 Internet Explorer 5.5+ 支持
defer
,正如您在 CanIUse.com 中看到的那样,如果异步不可用,我想优雅地回退到使用 defer。我认为异步可用时最好使用它,但直到 Internet Explorer 10 才支持它。
我的问题是上面的代码是有效的 HTML 吗?如果没有,是否可以使用 JavaScript 创建这种情况,当
defer
不可用时,优雅地回退到在脚本上使用 async
?
来自规范:https://www.w3.org/TR/2011/WD-html5-20110525/scripting-1.html#attr-script-async
即使指定了 async 属性,也可以指定 defer 属性,从而导致仅支持 defer(而不是异步)的旧版 Web 浏览器回退到 defer 行为,而不是默认的同步阻塞行为。
(查看下面的参考链接,查看普通脚本与延迟和异步脚本之间差异的直观表示)
参考资料:
不幸的是,当指定
defer
时,async
会被忽略,并且 async
始终具有更高的优先级。
我个人认为
defer
被现代浏览器(支持async
)忽略是非常糟糕的。让我们想象一下当我们希望尽快初始化一些 JS 的情况,甚至在加载页面内容之前。但我们希望该脚本在需要它的其余脚本之前初始化。它应该位于 defer
队列中的第一个。但不幸的是,这行不通:
<!-- we want "jQuery" ASAP and still in "defer" queue. But defer is ignored by modern browsers. -->
<script src="jquery.min.js" async defer></script>
<!-- this doesn't blocks the content and can wait the full page load, but requires "jQuery" -->
<script src="some_jquery_plugin.min.js" defer></script>
在此示例中,“some_jquery_plugin.min.js”可以在加载 jQuery 之前加载并执行,但会失败。 :(
因此有两种方法可以解决这个问题:要么只使用
defer
指令,要么将所有依赖的 javascript 文件合并到单个 JS 中以安全地使用 async
。
问题是,您希望它做什么? 如果 async 和 defer 都存在,我希望脚本被推迟,并且仅在浏览器空闲时在 DOMContentLoaded 之后执行,但如果我正确阅读规范,如果 async ,则看起来 defer 被忽略 已设置并且脚本是异步加载的,因此将在可用时立即执行,这很可能在 DOMContentLoaded 之前执行,并且可能会阻止其他资源。
使用这些属性可以选择三种可能的模式。如果存在 async 属性,则脚本将在可用时立即异步执行。如果 async 属性不存在,但存在 defer 属性,则当页面完成解析时执行脚本。如果这两个属性都不存在,则在用户代理继续解析页面之前立即获取并执行脚本。
https://www.w3.org/TR/2011/WD-html5-20110525/scripting-1.html#attr-script-async
不。 您需要使用
defer
或 async
,但不能同时使用两者。有关更多信息,请参阅比较并根据您的需要使用。
defer属性:首先会下载脚本文件,然后等待html解析。 html解析结束后,脚本将被执行。换句话说,它将保证所有脚本在 html 解析后都会执行。
当脚本用于 DOM 操作时,Defer 属性非常有用。意味着脚本将应用于文档 html。
async 属性: 它将下载脚本文件并执行,无需等待 html 解析结束。换句话说,它不能保证所有脚本在 html 解析后都会执行。
当脚本不用于 DOM 操作时,异步属性非常有用。有时,您只需要脚本来进行服务器端操作或处理缓存或 cookie,而不需要 DOM 操作。意味着脚本与使用的 html 无关。
是的,它是有效的 HTML,并且会按预期工作。
任何符合 W3C 标准的浏览器都将识别 async 属性并正确处理脚本,而旧版 IE 版本将识别 defer 属性。
由于这两个属性都是 boolean,因此您不必必须分配任何值。
实际上,这里的大多数评论都存在误解。人们似乎不知道DEFER也可以并行加载代码,就像ASYNC一样。但它会在 DOM 加载后(但在 DOMContentLoaded 执行之前)等待执行,而 ASYNC 在加载后、DOM 加载之前立即运行它。由于 ASYNC 和 DEFER 都是并行加载代码的,因此无需同时使用两者(但也许是为了处理遗留问题)。