async和defer均不阻塞html解析,但执行时机迥异:async脚本下载完立即执行,可能中断解析且不保序;defer脚本等dom构建完毕后按序执行,可安全操作dom。

async 和 defer 都不阻塞 HTML 解析,但执行时机完全不同
这是最常被忽略的前提:两者都让 <script src="..."></script> 在后台异步下载,HTML 解析不会停。但「下载完之后干啥」,决定了它们的行为分野。
关键判断点是:脚本执行时 DOM 是否就绪、多个脚本是否按顺序跑。
-
async脚本一下载完就执行,不管 DOM 解析到哪——可能在还没开始解析时就跑了,此时document.getElementById会返回null -
defer脚本一定等到整个 HTML 解析完成(即DOMContentLoaded触发前)才执行,DOM 已完整,可安全操作元素 - 多个
async标签谁先下完谁先跑,顺序不可控;多个defer标签严格按 HTML 中出现顺序执行
哪些场景必须用 defer,不能用 async
当你写的 JS 依赖页面结构,比如初始化表单、绑定按钮点击、读取某个 <div id="app">,那就得选 <code>defer。
- 脚本里调用了
document.querySelector、addEventListener等 DOM API - 多个脚本有依赖关系,比如
utils.js必须在main.js之前执行 - 你希望所有脚本都在
DOMContentLoaded前执行完毕(例如埋点收集首屏元素) - 用
module的脚本默认带defer行为,加async会破坏模块加载顺序
async 更适合哪些第三方脚本
async 不是“更先进”,而是“更独立”。它只适合完全不依赖 DOM、也不依赖其他脚本的代码。
- 统计类脚本(如 Google Analytics、友盟),它们只发请求,不查 DOM
- 广告代码,通常自包含、带防错逻辑,且越早上报曝光越好
- 独立功能组件(如客服浮窗、分享弹层),内部自己处理 DOM 就绪检测
- 注意:
async脚本如果执行时 HTML 还在解析中,会短暂阻塞解析——这不是下载阻塞,而是执行阻塞
常见错误:把 defer 或 async 加在内联 script 上
这两个属性只对带 src 的外部脚本生效。写成这样毫无意义:
<script defer>console.log('hello');</script>
浏览器会直接忽略 defer 和 async,当作普通同步脚本执行。
另外,defer 放在 里没问题,但别指望它能“延迟到页面末尾”——它的延迟终点是 HTML 解析结束,不是 标签位置。真要保险,还是把脚本放 前更可控。











