HTML 的 defer 和 async 到底有什么区别加载顺序怎么选
**结论:要保证多个脚本按书写顺序执行、且能拿到完整 DOM,用 defer;脚本之间互不依赖、越早跑越好(埋点、统计、广告),用 async;必须在下游代码之前同步可用的库(如需要全局变量立即生效的 polyfill),才用普通 script。**
defer 和 async 到底有什么区别?
核心区别只有一句话:defer 只改变「执行时机」,async 改变「执行时机和执行顺序」。
两者相同的地方是「下载」阶段:带 defer 或 async 的外部脚本都会和 HTML 解析并行下载,下载过程不阻塞解析,所以都不会像普通 <script> 那样一遇到就卡住页面。
不同的地方在下载完成之后:defer 脚本会老老实实排队,等整个 HTML 解析完再按文档中出现的先后顺序依次执行;async 脚本是「谁先下载完谁先执行」,执行的那一刻会打断 HTML 解析,跑完再继续解析。
另外两个必须记住的约束:defer 和 async 只对外部脚本(带 src)生效,写在行内 <script> 上的这两个属性会被浏览器直接忽略;defer 保证顺序,async 不保证任何顺序。
三者的加载和执行顺序分别是怎样的?
按时间线理解最清楚,假设页面里有两个脚本 a.js(大,下载慢)和 b.js(小,下载快):
- 普通
<script>:解析 HTML → 遇到脚本 → 暂停解析 → 下载 → 执行 → 继续解析。两个脚本严格按书写顺序,但下载期间的解析全部被阻塞。 <script defer>:解析 HTML 的同时并行下载 a.js、b.js → 解析完 → 按 a、b 的书写顺序执行 → 触发DOMContentLoaded。注意:a 虽然大,b 也必须等 a 先执行。<script async>:解析 HTML 的同时并行下载 → b.js 先下载完,就立刻执行 b,此时解析被暂停 → a.js 下载完后执行 a。所以实际执行顺序是 b、a,和书写顺序相反。
结论:defer 脚本一定在 DOMContentLoaded 事件之前执行完,async 脚本则不一定——DOMContentLoaded 不会等待 async 脚本。如果 a.js 下载特别慢,async 脚本甚至可能在 window.onload 之后才执行。所以依赖 async 脚本初始化 UI 是不可靠的。
defer 和 async 怎么选?
给三条可直接套用的判断规则:
- 脚本之间有依赖,或需要操作 DOM → 用 defer。比如
jquery.js+plugin.js,插件依赖 jQuery,必须保序;同时 defer 保证 DOM 已解析完,脚本里可以直接document.querySelector。 - 脚本完全独立、无依赖、希望尽早执行 → 用 async。典型是统计代码、错误监控、广告位 SDK,它们各自独立,早执行早上报。
- 必须同步可用,否则后续代码报错 → 用普通 script(可放
<head>或<body>末尾)。比如某个库必须在业务代码执行前挂到window上。
还要补两个现代事实:<script type="module"> 默认就是 defer 行为,按模块依赖顺序执行;给它加 async 就变成 async 行为。另外,用 JS 动态创建的脚本默认是 async 的:
const s = document.createElement('script');
s.src = 'a.js';
document.head.appendChild(s); // 默认 s.async === true,不保证顺序
如果动态插入也要保序,必须显式写 s.async = false;,这是很多「脚本偶发顺序错乱」bug 的根源。
有哪些容易踩的坑?
第一,别在 defer 脚本里用 document.write,解析已完成,写入会清空页面。第二,async 脚本不要假设 DOM 已就绪,需要 DOM 就自己包一层 document.addEventListener('DOMContentLoaded', ...)。第三,不要给行内脚本加 defer/async,无效且容易误判。第四,如果脚本是渲染关键路径上的一环(比如决定首屏布局的库),defer + <link rel="preload"> 预加载通常比 async 更稳。
收束
记住三句话就够了:下载阶段 defer 和 async 都不阻塞解析;defer 按书写顺序、在 DOMContentLoaded 前执行;async 谁先下载完谁先跑、时机不确定。选型公式是「要顺序或要 DOM → defer,要独立且要早 → async,要同步可用 → 普通 script」,动态插入脚本时记得手动设 async = false。
原文链接:https://www.gj0.com/thread-755.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。