页面卡住因script同步阻塞html解析与渲染;外部脚本应全用defer放head末尾,内联逻辑放body底部,第三方sdk需defer延后调用。

script放在里为啥页面卡住不动
浏览器解析HTML是自上而下流式进行的,遇到<script></script>标签会立即下载、编译、执行——期间阻塞DOM构建和渲染。放在里的同步脚本,尤其带网络请求或大体积逻辑的,会让白屏时间明显拉长。
- 默认
<script src="a.js"></script>就是同步阻塞行为,不管它多小 - 即使脚本本身没报错,只要执行耗时>100ms,用户就能感知“页面没反应”
- 某些老项目还用
document.write(),那更得等它执行完才能继续解析后续HTML
async和defer到底该选哪个
二者都让脚本不阻塞HTML解析,但触发时机和执行顺序完全不同,选错会导致undefined或document is not ready错误。
-
async:下载与HTML解析并行,**下载完立刻执行**,不保证顺序——适合彼此无依赖的统计、埋点脚本 -
defer:下载与HTML解析并行,但**等到DOM解析完成(DOMContentLoaded前)才按顺序执行**——适合操作DOM或依赖其他defer脚本的场景 - 注意:
async在IE9-完全不支持;defer在IE9+支持,但IE9对内联defer有bug,建议只用于外部脚本
动态创建script标签能绕过阻塞吗
可以,但不是万能解法。手动document.createElement('script')插入的脚本默认是异步的,但需自己处理加载完成和错误回退。
- 它天然等效于
async行为:下载完即执行,不保序 - 必须监听
onload和onerror,否则失败静默,调试困难 - 示例:
const s = document.createElement('script');<br>s.src = '/js/app.js';<br>s.onload = () => console.log('loaded');<br>s.onerror = () => console.error('load failed');<br>document.head.appendChild(s); - 如果脚本需要访问
window.jQuery这类全局变量,得确保它比jQuery先加载——动态创建不解决依赖问题
现代项目里真正该放哪儿
结论很直接:**外部脚本全用defer,放末尾;内联初始化逻辑放底部;关键首屏逻辑考虑内联+type="module"(自带defer语义)**。
-
type="module"脚本默认defer,且支持import依赖管理,比拼路径字符串靠谱得多 - Webpack/Vite打包产物通常已加
defer或自动注入async,别手动覆盖 - 最容易被忽略的是第三方SDK(比如微信JS-SDK、支付宝API),它们文档常写“放在
”,但实际应改用defer+WXJSSDK.config()延后调用,否则可能因DOM未就绪报错
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











