defer 不影响 HTML 首包传输与解析,仅推迟 JS 执行至 HTML 解析完成、DOMContentLoaded 触发前;首包大小、TTFB 和分块节奏均由服务端控制,defer 不干预。

defer 不影响 HTML 首包(first HTML chunk)的传输或解析速度,它只改变 JS 执行时机——执行被推迟到首包解析完成之后,但首包本身不受任何拖慢。
defer 对 HTML 首包传输和解析完全无干预
浏览器收到第一个 TCP 数据块(即首包)后,就立刻开始流式解析 HTML。遇到 <script src="a.js" defer> 时,它只做两件事:发起 a.js 的下载请求、继续往下解析 HTML。这个过程不暂停、不等待、不重排网络优先级。
- 首包大小、TTFB、HTML 分块发送节奏,全由服务端控制,
defer不参与也不改变 - 即使 a.js 是 5MB 大文件、CDN 延迟高,也不会让首包变大或变慢
- 对比无
defer的同脚本:<script src="a.js"></script>会强制暂停首包后续解析,直到 a.js 下载+执行完——这才是真正拖慢首包“感知完成时间”的元凶
defer 脚本执行时,首包早已解析完毕
defer 脚本的执行点明确落在「HTML 解析器到达文档末尾」之后、「DOMContentLoaded 触发之前」。此时整个首包(以及所有后续接收到的 HTML chunk)不仅已接收完,而且 DOM 树已构建完成。
- 你可以在
defer脚本里安全调用document.getElementById或document.body.appendChild,无需担心元素不存在 - 但别误以为资源都 ready:图片、字体、
<link rel="stylesheet">的 CSSOM 仍可能未就绪,defer不等它们 - 如果脚本里写了
img.onload = () => {...}却没检查img.complete,很可能错过已缓存图片的加载完成事件
容易被忽略的副作用:首包“视觉完成感”提前,但 JS 执行延迟可见
页面内容(文字、结构)能更快渲染出来,用户看到首屏的时间变短;但依赖 JS 的交互(如按钮点击、轮播初始化)要等到所有 defer 脚本按序执行完才可用——这中间存在可感知的“空窗期”。
立即学习“前端免费学习笔记(深入)”;
- 典型现象:首屏文字秒出,但搜索框无法输入、导航菜单点不动,等 200ms 后才突然响应
- 若多个
defer脚本中某一个含同步长任务(如大数组.sort()、正则全局匹配超长字符串),会卡住后续所有脚本及DOMContentLoaded,延长该空窗期 - 构建工具(如 Vite)若把初始化逻辑内联进
<script>,你写的defer在最终 HTML 里根本不存在——得查生成后的源码确认
真正关键的不是“defer 是否影响首包”,而是它把 JS 执行从首包解析流程里彻底剥离——这解放了 HTML 解析,却把执行责任移交给了开发者:你得确保脚本足够轻、顺序合理、不隐含同步阻塞。



















