渲染进程:Render Process,是浏览器的内容的核心进程。可以说,一个 tab 内的每一个内容,都需要 Render Process 处理。
一个渲染进程的线程分拆
- Main thread(主线程): 处理用户事件,和 UI 事件,类似客户端的主线程。
- Worker Threads (注意是复数,线程池): Web worker 和 Service Worker 工作线程池
- Compositor and raster threads (合成器和光栅化线程): 负责高效的渲染页面内容
- 合成器线程
- 光栅化线程
总体来看,渲染进程的核心工作就是将 HTML/CSS/JS 转为每一帧可以和用户交互的网页。

解析 DOM (Document Object Model) 结构
- 将 HTML 解析为一个 DOM 树(虚拟结构)
- 为了高效并发,Preload 扫描器会在生成 DOM 的同时,并发的请求以下资源:
- Images
- CSS
- JS Code
- 注意扫描到 JS Code,会阻塞视图树的解析,因为 JS 代码可能会通过操作 DOM 对象来改变整个 DOM 结构 (document.createElement).
- 如果确定 JS 代码中没有改变 DOM 结构,可以加上 async 和 defer,告诉浏览器这些 JS Çode 可以异步加载(注意是异步加载这些 JS Code),不会影响 DOM 结构。
- 当然还有些资源对浏览器来说必不可少,必须提前尽快加载,可以使用 link preload 关键字:
<link rel="preload">
CSS样式计算
- CSS 通过 CSS-Selector 给每个元素设定计算样式
- 即使代码中没有显示的设置任何 CSS 样式,浏览器也会给每个 DOM 结构默认的样式,例如 <H1> 会比 <H2> 大。
Layout Tree 布局树 (Render Tree 很多地方叫做渲染树)
目前还不足以渲染一个网页,主线程还需要遍历DOM结合着CSS布局样式,构造出一棵布局树。布局树整体结构和 DOM 结构类似 (例如,伪元素结点不一致 / visible等),但只需要记录每个元素的 Rect {x, y, width, height}。还有是否需要显示等。

布局是个非常艰巨的任务,在 Chrome 中,整个工程师团队都致力于布局中。
绘制序列 Paint Records

有了 DOM 树,计算样式,还有 Layout Tree;仍然不足以用来绘制一个页面。关键点就是 z-index,计算遮挡(图形学中叫做光栅化)。
主线程再次遍历整个布局树(渲染树),去创建一个 Paint Records (绘制记录)。一个绘制记录类似于:
1:背景绘制、
2、文本内容
3、矩形边框绘制。

到目前,主线程依次生成了:
- DOM tree (包含 style)
- Layout Tree
- Paint 记录 (线性的记录,表示每个元素需要绘制内容的顺序和步骤)

更新渲染管线是十分昂贵的,想象一下,如果 Layout Tree (Render Tree) 变化,然后布局的绘制记录就需要重新计算 (可能发生了遮挡关系的变化)。
Layer Tree
结合 Render Tree 和 绘制指令,最后生成一棵图层树 (Layer Tree)。这里会有图层的合成和合并,遮挡计算等。