优先选 defer,仅当脚本完全自包含且不读写 dom、不依赖其他脚本时才用 async;defer 仅对带 src 的外部脚本生效,内联脚本加 defer 无效。

直接结论:用 async 还是 defer,不看“要不要延迟”,只盯住两个事实:脚本是否读取或修改 DOM,以及是否依赖其他脚本的执行结果。
async 脚本里调 document.getElementById 报 null 怎么办
这是最典型的 async 误用现象——脚本下载完就立刻执行,此时 DOM 可能还没解析到目标元素。
- 确认该脚本是否真的不需要 DOM:比如埋点、广告 SDK、错误监控等“自包含”逻辑才适合
async - 如果脚本里有
document.querySelector、addEventListener或操作body,一律禁用async - 第三方库如
clipboard.min.js文档没明确写“支持异步加载”,就别加async;lodash.js加了async后,紧跟着用_.debounce很可能报ReferenceError
多个 defer 脚本为什么还是执行错乱
defer 保证执行顺序,但前提是它们都出现在同一份 HTML 中、且没混入 async 脚本。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
defer只对带src的外部脚本生效;内联<script defer>console.log(1)</script>的defer被浏览器忽略 - 页面里同时存在
<script defer src="a.js"></script>和<script async src="b.js"></script>,b.js可能在a.js执行中途插入运行,顺序彻底失控 - Webpack/Vite 打包出的
main.js,只要没做资源预加载,就该用defer;SSR 页面中,window.__INITIAL_STATE__注入必须在所有defer脚本之前,且不能加defer
Vue/React 入口脚本该用 defer 还是 async
绝大多数情况下选 defer。现代框架入口通常要挂载到 #app、读取服务端注入数据、或依赖 DOM 就绪状态。
- 用
async时,DOMContentLoaded可能还没触发,document.getElementById('app')就是null - 如果入口脚本内部用了
document.write(极少见),defer会失效甚至报错,此时只能放底部同步加载 - 动态 import() 拆分的代码块不受
defer/async影响,它们由 JS 引擎按需加载,无需额外标记
最容易被忽略的一点:defer 和 async 都只作用于外部脚本;而真实项目里,常有人把初始化配置写成内联 script 再加 defer,结果白加——浏览器根本不认。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










