真正的答案是:因为你不能相信 defer。
在概念上,defer 和 async 的区别如下:
async允许在后台下载脚本而不会阻塞。然后,在它完成下载的那一刻,渲染被阻止并执行该脚本。脚本执行后,渲染恢复。
defer做同样的事情,除了保证脚本按照它们在页面上指定的顺序执行,并且它们将在文档完成解析后执行。因此,某些脚本可能完成下载然后坐等稍后下载但出现在它们之前的脚本。
不幸的是,由于真正是标准的猫战,defer 的定义因规范而异,即使在最新的规范中也不能提供有用的保证。正如这里的答案和这个问题所展示的,浏览器实现 defer 的方式不同:
- 在某些情况下,某些浏览器会存在导致
defer
脚本乱序运行的错误。
- 一些浏览器将
DOMContentLoaded
事件延迟到defer
脚本加载之后,而有些则不会。
- 有些浏览器服从
defer
于<script>
与内嵌代码,并没有元素src
属性,有些忽略它。
幸运的是,规范至少指定了异步覆盖延迟。因此,您可以将所有脚本视为异步并获得广泛的浏览器支持,如下所示:
<script defer async src="..."></script>
全球 98% 的浏览器和美国 99% 的浏览器将通过这种方法避免阻止。
(如果您需要等到文档完成解析,请收听事件DOMContentLoaded
事件或使用 jQuery 的便捷.ready()
功能。无论如何您都希望这样做,以便在根本没有实现的浏览器上优雅地回退defer
。)