JavaScript—html文档渲染过程,css文件和js文件的下载,是否会阻塞渲染?

3 阅读7分钟

HTML 文档的渲染是一个多阶段协同的过程,核心分为「解析 → 布局 → 绘制」三大步骤;而 CSS 和 JS 文件的下载、执行,会通过不同方式影响渲染流程 —— 关键结论先明确:

  • CSS 文件:下载不阻塞 HTML 解析,但阻塞 DOM 渲染(布局 + 绘制),且阻塞后续 JS 执行;
  • JS 文件:下载和执行都会阻塞 HTML 解析(默认),也会阻塞 DOM 渲染;
  • 可通过 async/defer 关键字改变 JS 的阻塞行为。

一、先搞懂:HTML 文档完整渲染流程

浏览器加载 HTML 后,会按以下顺序执行流程(简化核心步骤):

  1. HTML 解析(Parse HTML) :浏览器从顶部开始逐行解析 HTML 文本,构建 DOM 树(Document Object Model) (描述页面结构的节点树);解析过程中遇到 <link rel="stylesheet">(CSS)、<script>(JS)、<img>(图片)等资源,会触发资源下载。

  2. CSS 解析(Parse CSS) :下载完成的 CSS 文件会被解析,构建 CSSOM 树(CSS Object Model) (描述样式规则的树);只有 DOM 树和 CSSOM 树都构建完成,才会进入下一步。

  3. 布局(Layout/Reflow) :结合 DOM 树和 CSSOM 树,计算每个 DOM 元素的位置、大小、间距等几何信息,生成「渲染树(Render Tree)」(仅包含可见元素,如 display: none 的元素不会进入渲染树)。

  4. 绘制(Paint) :根据渲染树,浏览器将元素的样式(颜色、背景、边框等)绘制到屏幕像素上,最终呈现可视化页面。

  5. 回流(Reflow)/ 重绘(Repaint) (后续可能触发):

    • 回流:元素几何信息变化(如宽高、位置),需重新执行「布局」步骤;
    • 重绘:元素样式变化(如颜色、背景),无需重新布局,直接重新「绘制」;回流开销远大于重绘。

二、CSS 文件:下载不阻塞解析,阻塞渲染 + JS 执行

1. 核心行为:

  • 下载不阻塞 HTML 解析:浏览器解析 HTML 时,遇到 <link rel="stylesheet"> 会并行下载 CSS 文件,同时继续解析后续 HTML(不会暂停解析)—— 因为 CSS 不影响 DOM 结构,提前解析 HTML 能提升效率。
  • 阻塞 DOM 渲染(布局 + 绘制) :渲染树需要 DOM 树 + CSSOM 树共同构建,缺少 CSSOM 树时,浏览器无法计算元素样式和位置,会暂停渲染流程,直到 CSS 下载并解析完成。→ 现象:如果 CSS 下载缓慢,页面会先显示 “空白”,直到 CSS 加载完成后才会渲染出样式。
  • 阻塞后续 JS 执行:JS 代码可能会操作 CSS 样式(如 document.styleSheets),为了避免 JS 读取到 “未完整解析的 CSS 样式”,浏览器会让 JS 等待前面的 CSS 下载 + 解析完成后,再执行 JS。→ 顺序依赖:<link rel="stylesheet"> 后面的 <script> 会被阻塞,直到 CSS 就绪。

2. 示例验证:

<!-- 解析 HTML 时,并行下载 style.css,同时继续解析后续 HTML -->
<link rel="stylesheet" href="style.css">
<!-- 这里的 JS 会等待 style.css 下载+解析完成后,才执行 -->
<script src="app.js"></script>
<!-- HTML 解析不会被 CSS 下载阻塞,会正常解析 div 节点 -->
<div class="box">Hello</div>
  • 现象:div 会被正常解析到 DOM 树,但不会立即渲染(无样式 + 阻塞),直到 style.css 加载完成,才会结合 CSSOM 树进行布局和绘制。

3. 优化建议:

  • 优先加载关键 CSS(如首屏样式内联到 <style> 标签,避免外部 CSS 阻塞);
  • 非关键 CSS 延迟加载(如通过 media="print" 标记,下载时不阻塞渲染,后续切换媒体类型);
  • 压缩 CSS 体积,使用 CDN 加速下载。

三、JS 文件:默认下载 + 执行都阻塞,可通过 async/defer 解除

JS 是「可修改 DOM/CSS」的脚本,浏览器无法预知 JS 会做什么(如 document.write 修改 DOM、document.style 修改 CSS),因此默认会严格阻塞流程,核心行为分「默认情况」和「async/defer 情况」:

1. 默认情况(无 async/defer):

  • 下载阻塞 HTML 解析:浏览器解析 HTML 时,遇到 <script> 会暂停 HTML 解析,先下载 JS 文件(单线程下载,早期浏览器不支持并行,现代浏览器支持有限并行,但解析仍会暂停)。
  • 执行阻塞 DOM 渲染:JS 下载完成后,会立即执行(单线程执行),执行期间会阻塞渲染流程(布局 + 绘制)—— 因为 JS 可能修改 DOM(如 appendChild)或 CSSOM(如 document.body.style.color = 'red'),浏览器需等待 JS 执行完成后,再重新同步 DOM/CSSOM 树。
  • 顺序依赖:JS 会按「在 HTML 中出现的顺序」下载 + 执行,后续 JS 需等待前面 JS 完成。

2. async 关键字:异步下载,执行不阻塞解析但阻塞渲染

  • 下载不阻塞 HTML 解析:JS 并行下载,HTML 解析继续(同 CSS 下载行为)。
  • 执行不阻塞 HTML 解析,但阻塞渲染:JS 下载完成后,会暂停当前 HTML 解析和渲染,立即执行 JS;执行完成后,恢复解析和渲染。
  • 顺序不保证:多个 async JS 的执行顺序由下载速度决定(谁先下载完谁先执行),不遵循 HTML 中的顺序。

3. defer 关键字:异步下载,延迟执行(不阻塞解析,可能阻塞渲染)

  • 下载不阻塞 HTML 解析:同 async,JS 并行下载,HTML 解析继续。
  • 执行不阻塞 HTML 解析,但可能阻塞渲染:JS 下载完成后,不会立即执行,而是等待整个 HTML 解析完成后(DOM 树构建完毕),再按「HTML 中出现的顺序」执行;执行时仍会阻塞渲染(因为 JS 可能修改 DOM/CSSOM),但此时 DOM 已完整,适合需要操作 DOM 的脚本。

4. 三者对比表:

特性默认(无关键字)asyncdefer
下载是否阻塞解析否(并行下载)否(并行下载)
执行是否阻塞解析是(下载完立即执行)否(HTML 解析完执行)
执行是否阻塞渲染
执行顺序按 HTML 顺序按下载速度(无序)按 HTML 顺序
适合场景需同步执行的脚本独立脚本(如统计、广告)依赖 DOM 的脚本(如初始化组件)

5. 示例验证:

<!-- 默认 JS:解析到这里暂停 HTML 解析,下载 app.js 并执行,再继续解析 -->
<script src="app.js"></script>

<!-- async JS:并行下载,下载完立即执行(暂停当前解析/渲染),顺序不确定 -->
<script src="stat.js" async></script>

<!-- defer JS:并行下载,HTML 解析完后按顺序执行 -->
<script src="init.js" defer></script>
  • 现象:app.js 会阻塞 HTML 解析,导致后续 DOM 节点延迟解析;stat.js 和 init.js 不会阻塞解析,但执行时仍会短暂阻塞渲染。

6. 优化建议:

  • 脚本放在 <body> 底部(默认情况):让 HTML 先解析完成,减少阻塞时间;
  • 依赖 DOM 的脚本用 defer(保证 DOM 完整,且按顺序执行);
  • 独立无依赖的脚本用 async(如统计、第三方 SDK,不影响主流程);
  • 避免同步加载大型 JS(会长时间阻塞解析和渲染);
  • 内联关键 JS(如首屏初始化逻辑,无需下载,减少阻塞)。

四、补充:图片等资源的下载与阻塞

  • 图片(<img>)、视频(<video>)等媒体资源:下载不阻塞 HTML 解析,也不阻塞渲染;
  • 但图片下载完成后,可能触发「回流」(如图片宽高未指定,下载后改变元素大小),导致页面重新布局和绘制 —— 因此建议给图片设置固定宽高或 aspect-ratio,避免回流。

五、核心结论总结

  1. HTML 渲染流程:解析 HTML 建 DOM → 解析 CSS 建 CSSOM → 结合生成渲染树 → 布局 → 绘制;

  2. CSS 文件

    • 下载不阻塞 HTML 解析;
    • 阻塞渲染(需等待 CSSOM 构建);
    • 阻塞后续 JS 执行;
  3. JS 文件

    • 默认:下载 + 执行都阻塞 HTML 解析,执行阻塞渲染;
    • async:下载不阻塞解析,执行阻塞解析 + 渲染,顺序无序;
    • defer:下载不阻塞解析,执行不阻塞解析(HTML 解析完执行),执行阻塞渲染,顺序有序;
  4. 优化核心:减少关键资源阻塞时间,让 DOM 和 CSSOM 尽快就绪,避免不必要的回流重绘。