您可以在 HTML 脚本标签上同时使用 async 和 defer 属性吗?

Posted

技术标签:

【中文标题】您可以在 HTML 脚本标签上同时使用 async 和 defer 属性吗?【英文标题】:Can you use both the async and defer attributes on a HTML tag? 【发布时间】:2012-11-29 01:24:38 【问题描述】:

我想同时使用 deferasync 加载以下 javascript 代码:

<script defer async src="/js/somescript.js"></script>

由于 Internet Explorer 5.5+ 支持 defer,正如您在 CanIUse.com 看到的那样,如果异步不可用,我想优雅地回退到使用 defer。我认为异步在可用时使用更好,但直到 Internet Explorer 10 才支持它。

因此,我的问题是上面的代码是有效的 html 吗?如果没有,是否有可能使用 JavaScript 在 async 不可用时优雅地回退到在脚本上使用 defer 来创建这种情况?

【问题讨论】:

见:***.com/a/68929270/7186739 【参考方案1】:

来自规范:https://www.w3.org/TR/2011/WD-html5-20110525/scripting-1.html#attr-script-async

即使指定了 async 属性,也可以指定 defer 属性,以导致仅支持 defer(而不是异步)的旧版 Web 浏览器回退到 defer 行为而不是默认的同步阻塞行为。

(查看下面的参考链接以直观地了解普通脚本与具有延迟和异步的脚本之间的差异)


参考资料:

async vs defer attributes Efficiently load JavaScript with defer and async

【讨论】:

这是真的吗?:1.asyncdefer 都存在,现代浏览器以async 运行; 2.asyncdefer都存在,旧浏览器以defer运行而不是default行为 不要异步和延迟做相反的事情吗? async 会同时加载脚本,但是在加载完成时执行(暂停页面解析),而 Defer 只会在所有加载和解析结束时执行? 如果存在 async 属性,则脚本将在可用时立即异步执行。如果 async 属性不存在但 defer 属性存在,则在页面完成解析后执行脚本。在这两种情况下,页面加载都不会被阻止。 @LeoMuller 这就是为什么它说“后备”。现代人更喜欢async 而不是defer。对@vikyd 表示肯定。如果您只是不关心遗产,那么您永远不想同时拥有两者 <script>【参考方案2】:

问题是,您希望它做什么? 如果 asyncdefer 都存在,我希望脚本被延迟并​​且仅在浏览器空闲时在 DOMContentLoaded 之后执行,但如果我正在阅读规范如果设置了 async 并且脚本是异步加载的,那么看起来 defer 会被忽略,因此将在它可用时立即执行,这很可能在 DOMContentLoaded 之前并可能阻塞其他资源.

使用这些属性可以选择三种可能的模式。如果存在 async 属性,则脚本将在可用时立即异步执行。如果 async 属性不存在但 defer 属性存在,则在页面完成解析后执行脚本。如果两个属性都不存在,则在用户代理继续解析页面之前立即获取并执行脚本。

https://www.w3.org/TR/2011/WD-html5-20110525/scripting-1.html#attr-script-async

【讨论】:

【参考方案3】:

不幸的是,defer 在指定async 时会被忽略,而async 始终具有更高的优先级。

我个人认为defer 被忽略是非常糟糕的。让我们想象一下我们希望尽快初始化一些 JS 的情况,甚至在加载页面内容之前。但是我们希望这个脚本在其他需要它的脚本之前初始化。它应该在defer 队列中排在第一位。但是,不幸的是,这不起作用:

<!-- we want "jQuery" ASAP and still in "defer" queue. But defer is ignored. -->
<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中。

【讨论】:

【参考方案4】:

是的,它是有效的 HTML,它会像预期的那样工作。

任何符合 W3C 的浏览器都会识别 async 属性并正确处理脚本,而旧版 IE 版本将识别 defer 属性。

由于这两个属性都是布尔值,因此您不必必须分配任何值。

【讨论】:

感谢 @jandy 的另一个精彩回复! "...将按预期工作。"你希望它做什么呢?!【参考方案5】:

是的,您可以同时使用这两个属性,但您需要使用 defer 或 async,不能同时使用。有关更多信息,请参阅比较并根据您的需要使用。

defer属性:首先会下载脚本文件,然后等待html解析。 html解析结束后,脚本将执行。也就是说,它会保证所有的脚本在html解析后都会执行。

当脚本用于 DOM 操作时,Defer 属性很有用。意味着脚本将应用于文档 html。

async 属性: 它会下载脚本文件并执行,无需等待 html 解析结束。也就是说,它不能保证所有的脚本都会在html解析后执行。

当脚本不用于 DOM 操作时,异步属性很有用。有时您只需要脚本用于服务器端操作或处理缓存或 cookie,而不需要用于 DOM 操作。表示脚本与使用的 html 无关。

【讨论】:

【参考方案6】:

其实这里大部分的cmets都有一个误解。人们似乎不知道 DEFER 也像 ASYNC 一样并行加载代码。但它会在 DOM 加载后等待执行(但在 DOMContentLoaded 执行之前),而 ASYNC 在加载后立即运行它,在 DOM 加载之前。由于 ASYNC 和 DEFER 都并行加载代码,因此无需同时使用两者(但可能要处理遗留问题)。

【讨论】:

以上是关于您可以在 HTML 脚本标签上同时使用 async 和 defer 属性吗?的主要内容,如果未能解决你的问题,请参考以下文章

script标签的async属性是用来异步加载,异步加载的作用是否同时下载,执行html代码和js代码

浅谈script标签中的async和defer

html中如何显示<script>本身

script标签中defer和async有什么不同?

脚本引用中使用defer和async用法和区别

理解JS中script标签defer和async属性