<script> 的 defer 和 async 的区别

4 分钟
54 阅读
<script> 的 defer 和 async 的区别

非常好的问题 👍
这是前端性能优化和脚本加载机制里非常关键的点。
我们来彻底讲清楚——<script>deferasync 的区别、执行顺序、应用场景👇


🧩 一、基础:浏览器加载 <script> 时发生了什么?

默认情况下,浏览器在加载 HTML 时遇到 <script> 会:

  1. 暂停 HTML 解析
  2. 开始下载脚本
  3. 下载完成后立即执行
  4. 执行完后再继续解析 HTML

所以,普通 script 会阻塞页面渲染👇

html 复制代码
<!-- 会阻塞 HTML 解析 -->
<script src="app.js"></script>
<p>这段文字要等上面脚本执行完才能渲染</p>

⚡ 二、asyncdefer 的出现:解决阻塞问题

✅ 1️⃣ async(异步加载、独立执行)

html 复制代码
<script src="a.js" async></script>
<script src="b.js" async></script>

特点:

特性 说明
加载方式 异步下载,不阻塞 HTML
执行时机 下载完成后立即执行(哪一个先下完先执行)
执行顺序 不确定!(谁先下载完谁先执行)
是否等待 DOM ❌ 不等待
适用场景 独立、不依赖其他脚本(如统计、广告)

🧠 举例:

html 复制代码
<!-- 这两个脚本会同时下载,但执行顺序随机 -->
<script src="track.js" async></script>
<script src="ads.js" async></script>

✅ 2️⃣ defer(延迟执行、按顺序执行)

html 复制代码
<script src="a.js" defer></script>
<script src="b.js" defer></script>

特点:

特性 说明
加载方式 异步下载,不阻塞 HTML
执行时机 HTML 解析完成后(DOMContentLoaded 前)执行
执行顺序 ✅ 按照在 HTML 中的顺序依次执行
是否等待 DOM ✅ 会等待 DOM 解析完成
适用场景 脚本依赖 DOM、依赖其他脚本(例如框架、初始化逻辑)

🧠 举例:

html 复制代码
<script src="react.js" defer></script>
<script src="main.js" defer></script>

👉 浏览器会:

  1. 同时下载 react.jsmain.js
  2. 等 HTML 解析完
  3. 按顺序执行 react → main

🧮 三、执行时序对比图

顺序 普通 <script> <script async> <script defer>
下载 ⏸️ 阻塞下载 ⏩ 异步下载 ⏩ 异步下载
执行时机 下载完立刻执行 下载完立刻执行 HTML 解析完后执行
执行顺序 按出现顺序 不确定 按出现顺序
是否阻塞 HTML ✅ 阻塞 ❌ 不阻塞 ❌ 不阻塞
是否等待 DOM ❌ 不等待 ❌ 不等待 ✅ 等待

🧠 四、使用建议总结

场景 推荐属性 理由
独立脚本(分析、广告、SDK) async 不依赖 DOM 和其他脚本
依赖 DOM 的脚本(主逻辑、框架) defer DOM 解析完成后执行,顺序可控
需要立刻执行(初始化前置) 主线程阻塞执行,保证顺序

🧩 五、实践案例:性能优化推荐写法

html 复制代码
<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8">
    <title>脚本加载优化示例</title>
    <!-- 框架依赖:延迟执行但保证顺序 -->
    <script src="react.js" defer></script>
    <script src="app.js" defer></script>

    <!-- 第三方统计:异步执行即可 -->
    <script src="analytics.js" async></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

💡 六、额外说明:模块化脚本(type="module")

如果是现代项目(例如 React、Next.js、Vue3),你会看到:

html 复制代码
<script type="module" src="main.js"></script>

这时:

  • type="module" 的脚本默认就是 defer 的行为
  • 不需要再加 defer
  • 可使用 import/export 模块语法

👉 相当于:

html 复制代码
<script type="module" src="main.js" defer></script>

✅ 七、总结一句话记忆

属性 行为总结
阻塞下载 + 阻塞执行(同步)
async 异步下载 + 下载完立即执行(无序)
defer 异步下载 + DOM 解析后按顺序执行

是否要我帮你画一个「script 加载与执行时序图」?
那样你会更直观地看到 asyncdefer 和普通加载的差别。

评论

评论

发表评论