defer 和 async 的区别

在网站测试中给出了以下建议

考虑减少链的长度,减小资源的下载大小,或推迟不必要的资源的下载以改善页面负载

然后在解决建议中有一条建议感觉容易实现

尽量减少关键资源的数量:消除它们,推迟其下载,将其标记为async,等等

然后在搜索中发现除了 async 外还有 defer 属性可以减少对性能的影响.

为了解它们的差别,查了点资料,记录下来。

传统上,脚本时通过以下方式引入

1
<script src="script.js"></script>

只要HTML解析器发现这一行,就会请求获取脚本,并执行脚本。完成此过程后,就可以继续进行解析,然后可以分析HTML的其余部分。

可以想象,此操作可能会对页面的加载时间产生巨大影响。

解决此问题的一种非常常见的方法是将脚本放在页面底部,紧接在结束</body>标签之前。

除此之外还可以使用 async and defer

deferasync 都是布尔属性,它们的用法如下所示

1
2
<script async src="script.js"></script>
<script defer src="script.js"></script>

这些属性仅在head里才有用,如果将脚本放在body里,它们不起作用

性能比较

脚本没任何属性

解析碰到脚本时,将会暂停,直到提取并执行脚本为止。完成此操作后,将继续解析。

脚本在body标签前

解析完成后提取脚本并执行

使用async

脚本通过异步获取,准备就绪后,HTML解析将暂停以执行脚本,然后将其恢复

使用defer

脚本通过异步获取,只有在 HTML解析完成后才执行。解析完成时就像将脚本放在body标签末尾一样,但是总体而言脚本执行早于完成,因为脚本是与HTML解析并行下载的。

总结

  • 二者都是异步去加载外部 JS 文件
  • async 是在外部 JS 加载完成后,浏览器空闲时,Load 事件触发前执行。而defer 是在 JS 加载完成后,整个文档解析完成后执行。
  • defer 更像是将<script>标签放在</body>之后的效果,但是它由于是异步加载 JS 文件,所以可以节省时间。
  • async 阻止页面解析,但 defer 不阻止
  • 同时使用 deferasync 时,如果浏览器支持 async 则按 async 解析;如果不支持,则按 defer 解析。