<脚本 defer=“defer”>究竟是如何工作的?

2022-08-30 01:06:26

我有几个元素,其中一些元素中的代码依赖于其他元素中的代码。我看到这个属性可以在这里派上用场,因为它允许代码块在执行时被推迟。<script><script>defer

为了测试它,我在Chrome上执行了这个:http://jsfiddle.net/xXZMN/

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

但是,它会提醒 。为什么它没有警报?2 - 1 - 31 - 2 - 3


答案 1

HTML5 规范中的一些片段:http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

如果 src 属性不存在,则不得指定延迟和异步属性。


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


由于大多数历史原因,这些属性的确切处理细节有些不平凡,涉及HTML的许多方面。因此,实现要求必然分散在整个规范中。下面的算法(在本节中)描述了这种处理的核心,但这些算法引用HTML,外国内容和XML中脚本开始和结束标签的解析规则,document.write()方法的规则,脚本的处理等引用。


如果元素具有 src 属性,并且该元素具有延迟属性,并且该元素已标记为“解析器插入”,并且该元素没有异步属性:

必须将该元素添加到脚本列表的末尾,当文档完成与创建该元素的解析器的文档关联的解析时,将执行该脚本列表。


答案 2

真正的答案是:因为你不能信任延期。

在概念上,延迟和异步的区别如下:

async 允许在后台下载脚本而不会阻塞。然后,在完成下载的那一刻,渲染将被阻止,并且该脚本将执行。脚本执行后,呈现恢复。

defer 执行相同的操作,但声明保证脚本按页面上指定的顺序执行,并在文档完成解析后执行。因此,某些脚本可能会完成下载,然后坐下来等待稍后下载但在它们之前出现的脚本。

不幸的是,由于这实际上是一场标准的猫之战,因此推迟的定义因规格而异,即使在最新的规格中也无法提供有用的保证。正如此处的答案和此问题所示,浏览器以不同的方式实现延迟:

  • 在某些情况下,某些浏览器存在导致脚本无序运行的错误。defer
  • 某些浏览器将事件延迟到脚本加载后,而有些浏览器则不会。DOMContentLoadeddefer
  • 一些浏览器服从具有内联代码且没有属性的元素,而有些浏览器则忽略它。defer<script>src

幸运的是,规范至少指定了异步覆盖延迟。因此,您可以将所有脚本视为异步脚本,并获得广泛的浏览器支持,如下所示:

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

全球98%的浏览器和美国99%的浏览器将避免使用这种方法进行阻止。

(如果您需要等到文档完成解析,请收听事件事件或使用jQuery的handy函数。无论如何,您都希望这样做,以便在根本没有实现的浏览器上优雅地回退。DOMContentLoaded.ready()defer