defer脚本不阻塞HTML解析,因其下载与解析并行,执行被推迟至DOM构建完成、DOMContentLoaded触发前;仅对外部src脚本生效,内联脚本加defer无效。

defer 属性能显著提升首屏渲染速度,但只对带 src 的外部脚本生效,且必须放在 或文档早期位置才起效。
defer 脚本为什么不会阻塞 HTML 解析
浏览器在解析 HTML 时,遇到 <script defer src="app.js"></script> 会立即发起下载请求,但不暂停 DOM 构建。这个下载过程和 HTML 解析完全并行——就像你一边听播客一边写代码,互不干扰。
关键点在于:defer 脚本的执行被明确推迟到整个 HTML 文档解析完成之后、DOMContentLoaded 事件触发之前。这意味着所有 DOM 节点都已就位,你可以放心调用 document.getElementById 或 querySelector,不用加监听或延时。
- 不适用于内联脚本:
<script defer>console.log('hi')</script>中的defer会被浏览器直接忽略 - 如果脚本里用了
document.write,defer 会失效(现代脚本基本不用这个 API,但老代码可能踩坑) - 多个 defer 脚本按 HTML 中顺序执行,哪怕
vendor.js比app.js下载慢,也一定先执行前者
defer 和 async 混用时谁说了算
如果一个 <script></script> 同时写了 async 和 defer,比如 <script src="a.js" async defer></script>,现代浏览器(Chrome 69+、Firefox 61+、Safari 12+)会以 async 为准——即下载完立刻执行,不再等待 DOM 解析完成,也不保证顺序。
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
这不是“优先级”问题,而是规范定义:当两者共存时,async 的语义覆盖 defer。所以别这么写,否则等于白加 defer。
- 想保序 → 只用
defer - 想尽快执行且无依赖 → 只用
async - 既想保序又想尽早执行?不行。defer 的“尽早”是 DOM 解析后,这是硬性前提
Webpack 或 Vite 构建产物里怎么安全加 defer
构建工具默认生成的 <script></script> 标签通常没加任何属性,直接塞进 就会同步阻塞。手动加 defer 最简单,但要注意两个地方:
- HTML 模板中,把
<script src="main.[hash].js"></script>改成<script src="main.[hash].js" defer></script>;注意不能加type="module"后再加defer——虽然合法,但模块脚本默认行为就类似 defer,再加反而冗余 - SSR 场景下,服务端吐出的 HTML 若已含
defer,客户端 hydration 时不需要额外处理;但如果服务端没加,而你在客户端用 JS 动态插入带defer的 script,它不会自动补上执行时机保障——defer 必须在初始 HTML 解析阶段就被识别 - 某些 CMS 或微前端框架会动态注入脚本,此时
defer属性无效,得改用addEventListener('DOMContentLoaded', ...)手动控制执行时机
容易被忽略的兼容性与 LCP 影响
IE10+、Edge 13+、所有现代浏览器都支持 defer,但 iOS Safari 10.3 之前有个 bug:多个 defer 脚本在页面有 <base> 标签时可能乱序执行。如果你还在支持这个版本,得加降级逻辑。
对 LCP(最大内容绘制)指标来说,defer 脚本本身不参与计算——它不阻塞渲染,也不影响图像、文本等元素的首次绘制。但它间接影响:如果 defer 脚本里包含动态插入首屏图片或懒加载逻辑,那它的执行延迟就会拖慢 LCP。所以别在 defer 脚本里做 document.createElement('img') 然后 append 到首屏区域,除非你确认 DOM 已 ready 且资源已缓存。
真正要盯住的,是 defer 脚本的下载耗时。如果它体积大、CDN 不稳、或者路径没走 HTTP/2 多路复用,下载时间长了,DOMContentLoaded 也会被拉长——虽然不阻塞渲染,但后续 JS 逻辑启动晚了,用户交互响应还是卡。


















