defer是解决脚本找不到dom元素最直接可靠的方式,前提是脚本需操作完整dom或存在依赖关系;它仅适用于带src的外部脚本,确保按声明顺序在dom解析完成、domcontentloaded事件触发前执行。

defer 是解决“脚本找不到 DOM 元素”最直接、最可靠的方式,前提是脚本之间有依赖或必须操作完整 DOM。
什么时候必须用 defer
当你的脚本里写了 document.getElementById、document.querySelector、addEventListener,或者初始化了 tf.min.js 这类需绑定 canvas 的库,且脚本放在 里时,就必须加 defer。否则浏览器可能在 DOM 还没建好时就执行脚本,报错 Cannot read property 'getContext' of null 或直接静默失败。
常见错误现象:
- 控制台没报错,但页面没反应(DOM 元素取不到,后续逻辑跳过)
- 本地快、线上慢时偶发白屏或功能失效(网络延迟放大了执行时机问题)
- 把脚本挪到
前能跑通,但破坏了模块组织结构或构建流程
多个 defer 脚本的顺序不能乱
defer 的核心保障之一是执行顺序严格按 HTML 中声明顺序。比如你有:
<script src="vendor.js" defer></script><script src="app.js" defer></script>
那么 app.js 一定在 vendor.js 执行完后才运行——这对依赖关系(如 jQuery → 插件 → 业务逻辑)至关重要。
注意点:
- 不要混用
async和defer:比如<script async src="a.js"></script><script defer src="b.js"></script>,a.js可能在 DOM 解析完成前就执行,b.js却等最后,导致 b 依赖 a 但 a 还没挂到全局 - 动态插入的脚本(
document.createElement('script'))默认带async行为,即使你手动设script.defer = true,部分老浏览器也不认,别赌兼容性 -
type="module"脚本天然具有defer效果,无需重复写,但要注意它还自带严格模式和顶层await支持
defer 不是万能的:哪些情况它救不了
defer 只解决“加载时机 + 执行顺序”,不解决“要不要加载”或“加载失败怎么办”。以下场景它无能为力:
- 某个按钮点击后才需要加载 ECharts,
defer会提前下载并执行整个库,浪费带宽和内存 - CDN 失败导致
tf.min.js404,defer脚本照样卡住,不会自动 fallback - 脚本内部用了
document.write(虽然现代代码基本不用),defer会直接忽略该属性,退化为阻塞行为
这类问题得靠运行时控制:用 import() 动态导入 + try/catch,或者预置加载状态和错误提示。
真正容易被忽略的是:defer 保证 DOM 就绪,但不保证资源就绪。比如你 defer 加载了一个模型文件(.json 或 .bin),脚本执行时 DOM 有了,但模型还在 fetch 中——这时候还得自己处理 loading 状态和 Promise 链。时机控制只是第一步,数据流控制得跟上。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











