defer和async延迟加载

82 阅读2分钟

一、核心区别对比

特性deferasync
加载时机与 HTML 解析并行加载与 HTML 解析并行加载
执行时机DOM 解析完成后,按顺序执行脚本加载完成后立即执行(可能打断 HTML 解析)
执行顺序严格按脚本在文档中的顺序执行不保证顺序,先加载完的先执行
阻塞情况仅在 DOM 解析完成后执行时阻塞加载完成后立即中断 HTML 解析执行
兼容性IE9+ 及现代浏览器IE10+ 及现代浏览器

二、执行流程演示(关键差异)

// 假设页面有以下脚本
<script src="a.js"></script>         // 普通脚本:阻塞解析
<script async src="b.js"></script>   // async:并行加载,加载完立即执行
<script defer src="c.js"></script>   // defer:并行加载,DOM 解析完成后按顺序执行
<script defer src="d.js"></script>   // defer:同上

// 执行顺序可能为:
// 1. 解析 HTML → 遇到 a.js → 阻塞解析,加载并执行 a.js
// 2. 继续解析 HTML → 并行加载 b.js、c.js、d.js
// 3. b.js 先加载完成 → 立即执行(中断 HTML 解析)
// 4. 继续解析 HTML → 完成 DOM 构建 → 按顺序执行 c.js → d.js → 触发 DOMContentLoaded

三、典型应用场景

  1. defer 的最佳场景

    • 需操作 DOM 的脚本(如 jQuery 插件)。
    • 多个有依赖关系的脚本(如先加载库,再加载依赖库的脚本)。
    <script defer src="https://cdn.tailwindcss.com"></script>
    <script defer src="custom-script.js"></script>
    <!-- 确保 Tailwind 先加载,再执行自定义脚本 -->
    
  2. async 的最佳场景

    • 独立功能脚本(如统计代码、广告脚本)。
    • 不依赖 DOM 结构且不影响其他脚本的资源。
    <script async src="https://www.googletagmanager.com/gtag/js"></script>
    <script async src="ad-script.js"></script>
    <!-- 无需关心执行顺序,加载完成即执行 -->
    

四、与普通脚本的性能对比

加载方式HTML 解析阻塞情况适用场景
无 defer/async遇到脚本立即加载并执行,阻塞 HTML 解析强阻塞必须立即执行的关键脚本
defer并行加载,DOM 解析完成后执行弱阻塞(仅执行阶段)需操作 DOM 且有依赖顺序的脚本
async并行加载,加载完成立即执行可能中断 HTML 解析独立功能、无需顺序的脚本

五、问题

1. 问:defer 和 async 哪个更适合加载第三方库?

    • 若库有依赖关系(如 React → ReactDOM),用 defer 保证顺序。
    • 若无依赖(如 Google Analytics),用 async 避免阻塞。

2. 问:defer/async 会影响 DOMContentLoaded 事件吗?

    • defer 脚本会在 DOMContentLoaded 之前执行(可能延迟该事件触发)。
    • async 脚本若在 DOM 解析完成前加载完成,会先执行脚本再触发事件

3. 问:动态创建的脚本默认是 defer 还是 async?

    • 动态创建的脚本(如 document.createElement('script'))默认是 async
    • 若需按顺序执行,需显式设置 script.defer = true