JS 文件对 DOM 和 CSSOM 的阻塞
JavaScript 在什么情况下会阻塞 DOM 和 CSSOM 的构建,以及如何避免
问题
页面加载过程中,JS 文件是否一定会阻塞 DOM 和 CSSOM 的构建?
解答
答案是:不一定。
会阻塞的情况
1. JavaScript 文件放置在 head 标签内部
当 JavaScript 文件被放置在 head 标签内部时,浏览器会先加载并执行 JavaScript 文件,然后才继续解析 HTML 文档。如果 JavaScript 文件过大或服务器响应时间过长,页面会一直处于等待状态,阻塞 DOM 和 CSSOM 的构建。
<head>
<script src="large-script.js"></script>
<!-- 页面会等待脚本加载和执行完成 -->
</head>
2. JavaScript 代码修改了 DOM 结构
在 JavaScript 执行时,如果对 DOM 结构进行了修改,浏览器需要重新计算布局(reflow)和重绘(repaint),这个过程会阻塞 DOM 和 CSSOM 的构建。
不会阻塞的情况
1. 使用 async 属性
异步加载 JavaScript 文件,脚本的下载和执行与其他工作同时进行。脚本加载完成后立即执行,不保证执行顺序。
<script src="script.js" async></script>
2. 使用 defer 属性
浏览器立即下载脚本文件,但延迟到文档解析完成后才执行。脚本按照在页面中出现的顺序执行。
<script src="script1.js" defer></script>
<script src="script2.js" defer></script>
<!-- script1 会在 script2 之前执行 -->
3. 使用 Web Workers
Web Workers 运行在后台线程,不会阻塞 DOM 和 CSSOM 的构建,可以利用多核 CPU 提高执行速度。
const worker = new Worker('worker.js');
worker.postMessage('start');
关键点
- 普通 script 标签在 head 中会阻塞 DOM 解析,应放在 body 底部或使用 async/defer
- async 适合独立脚本(如统计代码),下载完立即执行,不保证顺序
- defer 适合依赖 DOM 的脚本,按顺序执行且在 DOMContentLoaded 之前完成
- 修改 DOM 会触发 reflow 和 repaint,应尽量批量操作减少性能损耗
- Web Workers 适合处理耗时计算,不阻塞主线程
目录