脚本放中未加defer/async会导致document.getelementbyid返回null,因浏览器流式解析时遇script即暂停dom构建,此时尚未解析;defer确保外部脚本在dom构建完成、domcontentloaded前按序执行,async则一下载完立即执行且不保序。

脚本放错位置不是“页面慢一点”的问题,而是直接导致 document.getElementById 返回 null、事件绑定失效、首屏白屏——根源在浏览器流式解析 HTML 的机制。
为什么 <script></script> 放 里会找不到 DOM 元素
浏览器从上到下解析 HTML,遇到没加 defer 或 async 的 <script src="app.js"></script>,立刻暂停 DOM 构建,去下载、解析、执行 JS。此时 还没开始解析,document.getElementById("main") 当然返回 null。
- 典型报错:
Cannot set properties of null、undefined is not an object - 哪怕脚本只有一行
console.log("hi"),也会卡住整个页面渲染 - Chrome DevTools 中能看到
DOMContentLoaded时间远晚于first-contentful-paint
defer 和 async 到底该用哪个
两者都只对带 src 的外部脚本生效,行为差异极大,选错就出错。
-
defer:脚本并行下载,不阻塞 HTML 解析;等 DOM 构建完、DOMContentLoaded触发前,严格按 HTML 中出现顺序执行。适合主业务逻辑,比如utils.js必须在app.js前加载 -
async:脚本异步下载,一下载完就立刻执行,不管 DOM 是否就绪、也不管其他脚本顺序。只适合完全独立的脚本,如analytics.js、广告 SDK - 把
async脚本放在前,不代表它会“等页面加载完”——它仍可能比<header></header>还早执行,document.querySelector("header")返回null -
type="module"脚本默认自带defer行为,还支持顶层await和静态导入分析,现代项目优先用它
放在 前就万事大吉?别太乐观
把 <script src="app.js"></script> 移到
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











