浏览器架构与渲染流水线

深入理解浏览器的多进程架构、各个进程的作用、以及渲染流水线从 HTML 到像素的完整流程。


浏览器的多进程架构

现代浏览器采用多进程架构,而非早期的单进程设计。这种架构是为了解决:

  • 稳定性:一个标签页崩溃不会导致整个浏览器崩溃
  • 安全性:不同进程有不同权限,隔离恶意代码
  • 性能:可以利用多核 CPU

Chrome 的进程架构

进程 职责
Browser 主进程 地址栏、书签、前进后退、网络请求、文件访问
Renderer 渲染进程 每个标签页一个,负责页面渲染、JavaScript 执行
GPU 进程 处理 GPU 任务,如 CSS 动画、Canvas
Plugin 进程 浏览器插件
Utility 进程 网络服务等

渲染进程内部结构

每个渲染进程包含多个线程:

  • 主线程:执行 JavaScript、计算样式、布局、绘制
  • 合成线程:将图层合成为最终页面
  • 工作线程:运行 Web Worker

渲染流水线

从 HTML 到屏幕上的像素,页面要经过以下步骤:

HTML → DOM → CSSOM → Render Tree → Layout → Paint → Composite

1. 解析(Parsing)

浏览器解析 HTML,构建 DOM 树:

<html>
  <body>
    <div>Hello</div>
  </body>
</html>

解析后构建成树形结构,每个 HTML 标签对应一个 DOM 节点。

2. CSS 解析

浏览器同时解析 CSS,构建 CSSOM 树:

body { margin: 0; }
div { color: red; }

CSSOM 和 DOM 结合,形成 Render Tree(渲染树)。

3. 布局(Layout)

渲染树遍历,计算每个元素的位置和大小。这涉及到盒模型

4. 绘制(Paint)

将布局信息转换成像素,填充到各个图层。

5. 合成(Composite)

将多个图层合成为最终页面,交给 GPU 显示。


关键渲染路径优化

渲染流水线不是每次都完整执行。优化目标是最小化需要执行的工作

关键渲染路径

从请求 HTML 到首次渲染完成,经过:

  1. HTML 传输
  2. DOM 构造
  3. CSS 解析
  4. CSSOM 构造
  5. JS 执行(可能阻塞)
  6. Render Tree 构造
  7. Layout
  8. 首次 Paint

任何阻塞都会延迟首次渲染。

render-blocking CSS

CSS 默认是 render-blocking——必须等 CSSOM 构造完成才能渲染:

<!-- 会阻塞首次渲染 -->
<link rel="stylesheet" href="styles.css">

<!-- 非阻塞:先渲染无样式的 HTML,然后再应用样式 -->
<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">

parser-blocking JS

<script> 默认会阻塞 HTML 解析——因为 JavaScript 可能修改 DOM:

<!-- 阻塞 HTML 解析 -->
<script src="app.js"></script>

<!-- 不阻塞:async 异步下载,下载完立即执行 -->
<script async src="app.js"></script>

<!-- 不阻塞:defer 异步下载,等 DOM 解析完成后执行 -->
<script defer src="app.js"></script>

重排(Reflow)和重绘(Repaint)

触发重排的操作

  • 添加/删除元素
  • 元素位置、尺寸变化
  • 浏览器窗口大小变化
  • 获取某些属性(offsetWidth, offsetHeight 等)

触发重绘的操作

  • 颜色、背景等视觉属性变化(不触发重排)
  • visibility、outline 等变化

优化建议

// 错误:多次重排
element.style.left = '10px';
element.style.top = '20px';
element.style.width = '30px';

// 正确:一次重排
element.style.transform = 'translate(10px, 20px)';
element.style.width = '30px';

这一章想说的

浏览器从 HTML 到像素经过:解析 → CSSOM → Render Tree → Layout → Paint → Composite。

理解渲染流水线是性能优化的基础:

  • CSS 应尽量小且非阻塞
  • JS 应该异步加载(defer/async)
  • 避免频繁触发重排重绘
  • 使用 transform/opacity 做动画(只触发 composite,不触发 layout/paint)

延展阅读