async与defer本质区别在于执行时机:async下载完立即执行且不保证顺序,可能阻塞DOM解析;defer则等DOM解析完按序执行。
关键看脚本执行时机与 DOM 解析是否阻塞。async 是“下载不阻塞、执行也不保证顺序、一下载完就立刻执行”;defer 是“下载不阻塞、执行等 DOM 解析完、按书写顺序执行”。两者都让 不阻塞 HTML 解析,但后续行为完全不同。
打开浏览器开发者工具 → Elements 面板 → 找到 标签 → 直接看属性是否存在:
async="" 或 async(布尔属性,值可省略)→ 异步加载 + 立即执行defer → 延迟执行,等待 DOMContentLoaded注意:async 和 defer 不能共存,浏览器会忽略 defer(若同时存在,以 async 为准)。
用 Network 面板和 Performance 面板能直观验证:
async 脚本:在 HTML 解析过程中并行下载,一旦下载完成,立刻中断当前解析、执行脚本(可能 DOM 还没解析完),执行完再继续解析defer 脚本:并行下载,但执行被推迟到 DOMContentLoaded 事件前,且多个 defer 脚本严格按 出现顺序执行src)加 async 或 defer 无效,浏览器会忽略这两个属性因为 defer 保证脚本执行时 document 已完全解析(至少是 DOM Tree 构建完成),无需监听 DOMContentLoaded。而 async 脚本执行时机不可控,很可能 document.getE 返回
lementByIdnull。
async 加载的初始化脚本里直接查 document.body → 报错或未定义defer 在 IE9+、所有现代浏览器都支持;async 从 IE10 开始支持,IE9 及以下会退化为同步加载async;站点核心逻辑(如菜单初始化、表单绑定)优先用 defer
真正容易被忽略的是:即使用了 defer,如果脚本依赖另一个尚未加载完成的模块(比如没用 ES 模块 import 或没配好 crossorigin),仍可能因资源加载失败导致执行中断 —— 属性只管加载策略,不管依赖完整性。