async脚本下载完立即执行,可能中断html解析且不保序;defer脚本等dom就绪后按序执行,确保可安全操作dom。

async 和 defer 的本质区别在哪
关键看脚本是否阻塞 HTML 解析,以及执行时机是否受 DOM 就绪状态约束。async 脚本下载时不阻塞解析,但一旦下载完成就立即执行(可能在 DOM 构建中途),不保证顺序;defer 同样不阻塞解析,但会等到整个 HTML 解析完毕、DOM 构建完成后再按书写顺序执行。
哪些脚本适合用 async,哪些必须用 defer
适合 async 的:完全独立、无 DOM 依赖、不修改全局环境的脚本,比如埋点统计(analytics.js)、广告 SDK(adsense.js);必须用 defer 的:依赖 document 或其他脚本输出的模块,比如初始化 UI 组件、操作 DOMContentLoaded 的逻辑。
-
async不保证执行顺序,两个带async的<script></script>标签可能因网络响应快慢导致后写的先执行 -
defer仅对外部脚本生效(src属性存在),内联脚本加defer会被忽略 - 如果脚本有
document.write(),两种属性都禁用——它会清空当前文档
和 DOMContentLoaded 的关系怎么理清
defer 脚本的执行时机,严格等价于在 DOMContentLoaded 事件触发前、按顺序执行;而 async 脚本可能在该事件之前、之中甚至之后执行,完全不可控。如果你写了一个监听 DOMContentLoaded 的回调,又同时引入了 async 脚本,那回调里访问 DOM 是安全的,但 async 脚本内部访问 DOM 就得自己加判断。
- 想确保脚本在 DOM 就绪后运行?优先选
defer,别自己包一层addEventListener('DOMContentLoaded', ...) - 多个
defer脚本之间可以互相依赖,因为它们按<script></script>出现顺序执行 -
async脚本中若需 DOM,应主动检查document.readyState,或用if (document.body) { ... }简单兜底
实际部署时容易被忽略的细节
很多人以为加了 async 或 defer 就万事大吉,其实浏览器行为还受 HTTP 缓存、预加载器(preload scanner)、以及是否启用 module 类型影响。
- HTTP/2 推送的脚本不会触发预加载器扫描,
async/defer属性可能失效,得靠<link rel="preload">显式声明 -
type="module"的脚本默认表现类似defer(即使没写),且不支持async(除非显式加) - 服务端渲染(SSR)页面中,若脚本依赖首次渲染后的 DOM 结构(比如 canvas 初始化),
defer仍可能太早——得结合requestIdleCallback或IntersectionObserver延迟执行
defer 是更稳妥的选择;只有确认脚本绝对无依赖、且允许乱序执行时,才用 async。别为了“看起来更快”而牺牲稳定性。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











