当前位置: 首页 > news >正文

16、defer 和 async 区别

目录

一、先建立认知框架

二、三种加载方式的完整对比

时序图

核心属性对比

三、逐项深度解析

执行时机的本质差异

与 DOMContentLoaded 的关系

顺序保证的工程意义

对 DOM 的访问能力

四、动态创建 script 标签

五、module script 的加载行为

六、工程选型原则

七、两个面试回答模板

🏆 高分模板(展现系统性 + 工程深度)

📝 简答模板(30 秒快速作答版)

八、面试官常见追问


这道题是浏览器渲染原理的高频细节题,能答好的关键在于:不只说"defer 等解析完执行,async 下载完就执行",而是要讲清楚执行时机的本质差异、顺序保证、依赖关系的影响、以及工程中如何正确选型,这才是让面试官眼前一亮的回答方式。


一、先建立认知框架

"defer 和 async 都是为了解决普通 script 阻塞 HTML 解析的问题,两者都会并行下载 JS,区别在于执行时机不同:defer 等 HTML 解析完再执行,async 下载完立即执行。一个让 JS 靠后执行,一个让 JS 尽快执行。"


二、三种加载方式的完整对比

时序图

普通 script(阻塞): HTML: ===解析==[暂停]=====[恢复]===解析完成 JS: [下载][执行] defer(延迟执行): HTML: ===解析========================解析完成 JS: [----并行下载----] [执行] ↑ HTML 解析完才执行 async(异步执行): HTML: ===解析==========[暂停]==[恢复]===解析完成 JS: [----并行下载----][执行] ↑ 下载完立即执行,打断 HTML 解析

核心属性对比

维度普通 scriptdeferasync
下载时机立即,阻塞解析并行下载并行下载
执行时机下载完立即执行HTML 解析完后执行下载完立即执行
是否阻塞解析✅ 下载和执行都阻塞❌ 不阻塞⚠️ 执行时阻塞
执行顺序按 HTML 顺序按 HTML 顺序不保证顺序
DOMContentLoaded触发前执行触发前执行不确定

三、逐项深度解析

执行时机的本质差异

defer 的执行时机:

HTML 解析完成 ↓ DOMContentLoaded 事件触发之前 ↓ 按照 script 在 HTML 中出现的顺序执行 defer 脚本 ↓ DOMContentLoaded 事件触发
<script src="a.js" defer></script> <script src="b.js" defer></script> <script src="c.js" defer></script> <!-- 无论谁先下载完,执行顺序一定是 a → b → c -->

async 的执行时机:

哪个 JS 文件先下载完,哪个先执行 ↓ 执行时中断当前 HTML 解析 ↓ 执行完毕,恢复解析
<script src="a.js" async></script> <script src="b.js" async></script> <script src="c.js" async></script> <!-- 谁先下载完谁先执行,顺序完全不确定 --> <!-- 可能是 c → a → b,也可能是 b → c → a -->

与 DOMContentLoaded 的关系

"这是区分两者的一个关键细节,面试说出来是加分点。"

defer 与 DOMContentLoaded:

规范明确规定: defer 脚本必须在 DOMContentLoaded 事件触发之前执行完毕 所以: document.addEventListener('DOMContentLoaded', () => { // 此时所有 defer 脚本都已执行完 })

async 与 DOMContentLoaded:

async 脚本与 DOMContentLoaded 没有顺序保证: 情况一:JS 文件很小,解析完成前就下载完并执行了 → async 先执行,DOMContentLoaded 后触发 情况二:JS 文件很大,解析完成后才下载完 → DOMContentLoaded 先触发,async 后执行 完全取决于网络速度和文件大小,不可预测

顺序保证的工程意义

为什么顺序重要:

// a.js:定义了工具函数 function formatDate(date) { ... } // b.js:依赖 a.js 的函数 formatDate(new Date()); // 如果 b 先执行,formatDate 未定义,报错
<!-- defer 保证顺序,这样写是安全的 --> <script src="a.js" defer></script> <script src="b.js" defer></script> <!-- async 不保证顺序,b 可能先于 a 执行,导致报错 --> <script src="a.js" async></script> <script src="b.js" async></script> <!-- 危险! -->

对 DOM 的访问能力

defer 执行时 DOM 已构建完成:

// a.js(defer 加载) document.querySelector('.header').style.color = 'red'; // ✅ 安全,执行时 HTML 已解析完,DOM 完整

async 执行时 DOM 不一定完整:

// a.js(async 加载) document.querySelector('.header').style.color = 'red'; // ⚠️ 危险!如果在 HTML 解析完成前就执行了 // .header 元素可能还没解析到,querySelector 返回 null

四、动态创建 script 标签

"面试中经常追问的边界场景。"

const script = document.createElement('script'); script.src = 'app.js'; document.head.appendChild(script);

动态创建的 script 标签默认行为是 async:

// 等价于 <script src="app.js" async></script> // 如果需要 defer 行为(保证顺序),需要显式设置: script.async = false;

这是很多脚本加载器(Script Loader)和模块打包工具的底层实现细节。


五、module script 的加载行为

"ES Module 默认就是 defer 行为,也是面试加分点。"

<!-- type="module" 默认等同于 defer --> <script type="module" src="app.js"></script> <!-- 等价于 --> <script src="app.js" defer></script>
<!-- module 也可以加 async,变成 async 行为 --> <script type="module" src="app.js" async></script>

module 的特点:

① 默认 defer 行为 ② 严格模式('use strict') ③ 模块作用域(变量不污染全局) ④ 同一模块只加载一次(即使多次 import) ⑤ 支持 import/export 语法

六、工程选型原则

选 defer 的场景: ✅ 有依赖关系的脚本(需要按顺序执行) ✅ 需要访问完整 DOM 的脚本 ✅ 大多数业务逻辑脚本 ✅ 框架初始化脚本(React、Vue 入口文件) 选 async 的场景: ✅ 完全独立、无依赖的脚本 ✅ 不操作 DOM 或不依赖 DOM 完整性 ✅ 第三方统计脚本(Google Analytics、埋点) ✅ 广告脚本 ✅ 不影响主要功能的辅助脚本 不用属性的场景: ✅ 必须立即执行的关键初始化代码(如检测浏览器特性) ✅ 内联脚本(无法加 async/defer,内联脚本直接执行)

七、两个面试回答模板


🏆 高分模板(展现系统性 + 工程深度)

"defer 和 async 都是为了解决普通 script 阻塞 HTML 解析的问题,两者都会让 JS 文件并行下载,不阻塞 HTML 解析,区别在于执行时机和顺序保证上。

先说 defer。defer 的脚本会在 HTML 解析完成之后、DOMContentLoaded 事件触发之前按顺序执行。注意是按照 script 在 HTML 中出现的顺序,无论哪个文件先下载完,都等所有 defer 脚本准备好后按序执行。所以多个 defer 脚本之间有明确的顺序保证,可以有依赖关系。另外 defer 执行时 DOM 已经构建完成,可以安全访问任意 DOM 节点。

再说 async。async 的脚本是哪个先下载完哪个先执行,不保证顺序,执行时机是下载完立即执行,会打断当前的 HTML 解析。async 和 DOMContentLoaded 也没有顺序保证,如果文件很小解析前就下载完了就先执行,如果文件大解析完才下载完就在 DOMContentLoaded 之后执行,完全取决于网络。

两者最关键的差异可以用一句话总结:defer 让 JS 尽量靠后执行,保证顺序,保证 DOM 完整;async 让 JS 尽量快执行,不保证顺序,不保证 DOM 状态。

工程选型上,有依赖关系的业务脚本、需要操作 DOM 的脚本都应该用 defer,React、Vue 这类框架的入口文件用 defer 很合适;完全独立的第三方脚本比如埋点、广告,用 async 更合适,早点执行不影响其他。

有两个细节值得一提:第一,动态创建 script 标签默认是 async 行为,如果需要保证顺序要显式设置script.async = false;第二,ES Module 的type=module默认就是 defer 行为,这是规范层面的设计,因为模块通常有依赖关系,需要顺序保证。"


📝 简答模板(30 秒快速作答版)

"defer 和 async 都能让 JS 并行下载,不阻塞 HTML 解析,区别在执行时机。

defer:HTML 解析完成后按顺序执行,在 DOMContentLoaded 之前。多个 defer 脚本严格按出现顺序执行,可以有依赖关系,执行时 DOM 已完整。

async:下载完立即执行,执行时会打断 HTML 解析。多个 async 脚本谁先下载完谁先执行,顺序不保证,与 DOMContentLoaded 没有顺序关系。

选型原则:有依赖、需要访问 DOM 的业务脚本用 defer;完全独立的第三方脚本(埋点、广告)用 async。

补充一个细节:ES Module 的type=module默认是 defer 行为;动态创建的 script 标签默认是 async 行为,想保证顺序要设置script.async = false。"


八、面试官常见追问

追问答题方向
"defer 和把 script 放 body 底部有什么区别?"defer 可以放 head,下载和 HTML 解析并行;放底部要等 HTML 解析完才开始下载,defer 性能更好
"async 的执行会阻塞渲染吗?"会,执行时会打断 HTML 解析,从而延迟渲染
"多个 async 脚本能保证顺序吗?"不能,谁先下载完谁先执行,有依赖关系的脚本不能用 async
"defer 一定在 DOMContentLoaded 前执行吗?"是的,规范明确规定 defer 脚本在 DOMContentLoaded 触发前执行完毕
"动态插入的 script 是什么行为?"默认 async,可以设置script.async = false改为 defer 行为
"type=module 和 defer 有什么区别?"行为类似,module 额外有严格模式、模块作用域、只加载一次、支持 import/export
"内联 script 可以加 defer 或 async 吗?"不行,defer 和 async 对内联脚本无效,内联脚本总是立即执行
http://www.cnnetsun.cn/news/1785905.html

相关文章:

  • 抖音批量下载终极指南:揭秘3步搞定无水印视频采集的实战技巧
  • Linux日常学习4
  • 神经符号AI:软件测试智能化的革命性引擎
  • 【2026毕业党救命帖】亲测AIGC率从59%速降至6%!5款神仙工具+6大手改公式全公开
  • 5分钟掌握AccelStepper:新手也能快速上手的步进电机终极指南
  • 【青少年CTF S1·2026 公益赛】哦
  • 智能车浅谈——控制规律篇
  • 您知道十万级用户到亿级用户系统架构是如何演进的吗?
  • CodeMagicianT屏
  • OpenHarmony学习笔记——点亮你的LED
  • Obsidian PDF++:如何用链接式注释重构PDF知识管理范式?
  • Linux内存管理(136):PageAnon 与 PageSwapBacked
  • 2025届最火的十大AI辅助论文工具推荐榜单
  • 终极Gmail桌面应用开发指南:从源码到专业级邮件客户端部署
  • PHP条形码生成利器:从入门到精通的barcode.php实战指南
  • Windows平台即时通讯消息保护技术:基于二进制补丁的防撤回解决方案
  • SDMatte惊艳作品集:影视级视觉特效与创意合成案例
  • 哪吒轮腿车模
  • Pixel Script Temple 构建AI Agent:自主任务规划与执行代码生成
  • 为什么你的回测收益在实盘归零?R 4.5中4类隐性交易成本建模(冲击成本/跨市场延迟/交易所撮合规则映射)深度拆解
  • 终极二次元游戏模组管理指南:XXMI启动器一站式解决方案
  • 【前端】1h 搞定 TypeScript 教程_只说重点
  • Common Voice 开源语音数据集技术深度解析与架构实现机制
  • 技术突破:iOS设备本地.deb到.ipa无缝转换创新解决方案
  • Spring Boot 3.4 + Java 25虚拟线程生产级接入全路径(含压测对比+GC调优数据)
  • Cursor Pro功能解锁工具:突破AI编程限制的全流程解决方案
  • 3大突破:AI智能体全栈实现与快速开发指南
  • XHS-Downloader终极指南:5分钟掌握小红书内容下载神器
  • translategemma-4b-it实战体验:Ollama部署,实测翻译英文图片说明书
  • HWA_09leetcode697数组的度