defer 和 async 的区别

288 阅读3分钟

deferasync 的区别

两者都是用于优化 JavaScript 文件的加载,防止阻塞 HTML 解析。但它们的行为有所不同,主要体现在加载顺序执行时机上。


1. defer

特点

  1. 加载过程

    • 脚本文件会在 HTML 解析的同时并行加载,不阻塞 HTML 的解析。
  2. 执行顺序

    • 脚本的执行会在 HTML 完全解析(即 DOM 结构生成完成)后按顺序执行。
    • 多个带 defer 的脚本会按它们在 HTML 中的顺序依次执行。
  3. 依赖性

    • 适合脚本之间有依赖关系的情况,保证执行顺序。

典型应用场景

  • 用于加载需要 DOM 解析完成后运行的脚本,比如页面逻辑代码。
  • 如加载多个脚本文件,且需要按顺序执行(例如库依赖关系)。

代码示例

<script src="script1.js" defer></script>
<script src="script2.js" defer></script>
<!-- 执行顺序:先执行 script1.js,后执行 script2.js -->

2. async

特点

  1. 加载过程

    • 脚本文件同样会在 HTML 解析的同时并行加载,不阻塞 HTML 的解析。
  2. 执行顺序

    • 脚本的执行会在文件加载完成后立即执行,不等待 HTML 解析完成,也不管脚本的加载顺序。即在 async 脚本加载完成后立即执行 时,会阻塞 HTML 的解析
    • 多个带 async 的脚本会根据文件加载完成的顺序执行,顺序不确定。
  3. 依赖性

    • 不适合脚本之间有依赖关系的情况,可能导致执行顺序错误。

典型应用场景

  • 用于加载独立的脚本,比如统计工具、广告脚本等,不依赖于其他脚本或 DOM。

代码示例

<script src="script1.js" async></script>
<script src="script2.js" async></script>
<!-- 执行顺序:由 script1.js 和 script2.js 的加载完成时间决定 -->

两者对比

特性deferasync
加载方式并行加载脚本文件,不阻塞 HTML 解析并行加载脚本文件,不阻塞 HTML 解析
执行时机HTML 完全解析完成后(DOM 生成后)再执行脚本加载完成后立即执行,不等待 HTML 解析
执行顺序按 HTML 中的顺序执行根据加载完成的先后顺序执行,顺序不确定
脚本依赖性支持脚本依赖关系,保证执行顺序不支持脚本依赖关系
适用场景需要 DOM 结构、脚本有依赖关系独立脚本,无依赖关系

总结使用建议

  1. 使用 defer

    • 如果脚本需要在 HTML 解析完成后运行,并且多个脚本之间存在依赖关系(例如库和业务代码)。
    • 推荐给页面逻辑代码加上 defer,确保脚本按顺序执行,并且不会影响首屏渲染。
    <script src="main.js" defer></script>
    
  2. 使用 async

    • 如果脚本是独立的,不依赖其他脚本或 DOM,可以用 async 优化加载速度。
    • 常见场景:第三方统计工具、广告、用户行为分析等。
    <script src="analytics.js" async></script>
    
  3. 不要同时使用 deferasync

    • 两者功能互斥,浏览器会忽略 defer 属性,仅按 async 行为处理。

普通 <script> 标签的对比

加载方式HTML 解析是否阻塞脚本加载是否阻塞 HTML 解析脚本执行时机执行顺序
普通 script阻塞阻塞立即执行(加载完成后)按 HTML 顺序
defer不阻塞并行加载DOM 解析完成后再执行按 HTML 顺序
async不阻塞并行加载加载完成后立即执行加载完成顺序(不确定)

图示说明

WechatIMG135.jpg