浏览器的多进程架构
现代浏览器采用多进程架构,而非早期的单进程设计。这种架构是为了解决:
- 稳定性:一个标签页崩溃不会导致整个浏览器崩溃
- 安全性:不同进程有不同权限,隔离恶意代码
- 性能:可以利用多核 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 到首次渲染完成,经过:
- HTML 传输
- DOM 构造
- CSS 解析
- CSSOM 构造
- JS 执行(可能阻塞)
- Render Tree 构造
- Layout
- 首次 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)