你能在HTML标签上同时使用async和defer属性吗?

108
我想使用deferasync同时加载以下JavaScript代码: <script defer async src="/js/somescript.js"></script> 由于Internet Explorer 5.5+支持defer(在CanIUse.com中可以看到),我希望在async不可用时能够优雅地回退到使用defer。我认为当它可用时,async更好,但直到Internet Explorer 10才支持。
我的问题是上面的代码是否有效的HTML?如果无效,则是否可以使用JavaScript来创建这种情况,在async不可用时优雅地回退到使用defer

请参见:https://dev59.com/xmYr5IYBdhLWcg3wQYFa#68929270 - Billu
6个回答

151

5
真的吗?1. asyncdefer都存在,现代浏览器会以async方式运行;2. asyncdefer同时存在,旧版浏览器会以defer而不是默认行为运行。 - vikyd
不是异步和延迟相反吗?异步会同时加载脚本,但在完成加载后执行(暂停页面解析),而延迟仅在所有加载和解析结束时执行? - Leo Muller
3
如果存在async属性,则脚本将异步执行,一旦可用就会执行。如果不存在async属性但存在defer属性,则脚本将在页面解析完成后执行。在这两种情况下,页面加载不会被阻塞。 - dave
@LeoMuller 这就是为什么它说“fallback”。现代的更喜欢使用async而不是defer。对于@vikyd的问题,我的回答是肯定的。如果您不关心遗留问题,您永远不会想在同一个<script>上同时使用两者。 - Константин Ван
@dave,再明确一下:async将异步下载,但可能会阻塞DOM解析(例如,当直接从缓存中提供时)。对于“在这两种情况下,页面加载不会被阻塞”的澄清。 - odus-ex

26

很遗憾,当指定async时,defer会被忽略,而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文件。

将所有依赖的JS文件合并为一个单独的JS文件可能会导致性能问题,因为捆绑包的大小可能会增加,因此需要再次将捆绑包拆分成块。 - Sachin Jain

23
问题是,您期望它做什么? 如果同时存在 async 和 defer,则预计将脚本延迟并在浏览器空闲时于 DOMContentLoaded 后执行。但是,如果我正确阅读规范,似乎如果设置了 async 并且异步加载脚本,则会忽略 defer,因此脚本将在可用时立即执行,这可能会在 DOMContentLoaded 之前执行,并可能阻止其他资源。
引用: 可以使用这些属性选择三种可能的模式。如果存在 async 属性,则脚本将异步执行,一旦可用即可执行。如果不存在 async 属性但存在 defer 属性,则在页面完成解析时执行脚本。如果两个属性都不存在,则会立即获取和执行脚本,而不会等待用户代理继续解析页面。

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


12
不需要同时使用deferasync。根据您的需求,可以参考比较并选择其中一个。 defer属性:首先下载脚本文件,然后等待HTML解析。在HTML解析结束后,脚本将执行。换句话说,它将保证所有脚本都在HTML解析之后执行。
当脚本用于DOM操作时,延迟属性很有用。这意味着脚本将应用于文档HTML。 async属性:它将下载脚本文件并在不等待HTML解析结束的情况下执行。换句话说,它不能保证所有脚本都在HTML解析之后执行。
当脚本不用于DOM操作时,异步属性很有用。有时您只需要脚本进行服务器端操作或处理缓存或cookie,而与所使用的HTML无关。

enter image description here


3
这个答复出现在谷歌搜索中,当搜索“我可以同时使用async和defer吗?”。它应该以“不”,而不是“是”开始。 - Jeremie
在当前图像版本中,在顶部的<script>部分,正确的绿色部分不应该更长一些吗? - Abdull

11

是的,它是有效的HTML,而且它将按预期工作。

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

由于两个属性都是布尔型,所以不需要分配任何值。


感谢 @jandy 的又一次出色回答! - Jasdeep Khalsa
12
“...会像预期的那样正常工作。”但你预期它会做什么呢?! - Patrick Clancey

1

实际上,这里大多数评论中存在误解。人们似乎不知道DEFER也会像ASYNC一样并行加载代码。但是它会等待DOM加载后执行(但在DOMContentLoaded执行之前),而ASYNC会在加载之后立即运行,DOM加载之前。由于ASYNC和DEFER都可以并行加载代码,因此没有必要同时使用两者(但可能需要处理遗留问题)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接