我很喜欢这句话:浏览器,是人类历史上计算机与科学技术领域最伟大的工艺品之一。在它背后,你能真切地感受到顶尖科学家是如何优雅地解决复杂问题的。
目录
一句话摘要
本文详细解析了浏览器从收到 HTML 文档到最终在屏幕上绘制出页面的全过程,涵盖了渲染主线程与合成线程的协同工作机制。
浏览器的渲染流程
面试高频 Q&AQ: 浏览器是如何渲染页面的? A: 当浏览器的网络线程收到 HTML 文档后,会产生一个渲染任务,并将其传递给渲染主线程的消息队列。在事件循环机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。
整个渲染流程分为多个阶段:HTML解析、样式计算、布局、分层、绘制、分块、光栅化、画。每个阶段都有明确的输入输出,上一个阶段的输出会成为下一个阶段的输入,形成了一套组织严密的生产流水线。

渲染主线程的工作原理
渲染主线程负责将 HTML 转换为带样式的 DOM 树,并生成绘制指令。(阶段 1-5)
1. HTML 解析 (Parse HTML)
从字符串到 DOM 树与 CSSOM 树。
面试高频 Q&AQ: CSS 会不会阻塞 HTML 解析?JS 呢? A:
- CSS 不会阻塞 HTML 解析:如果主线程解析到
link位置,此时外部的 CSS 文件还没有下载解析好,主线程不会等待,而是继续解析后续的 HTML。这是因为下载和解析 CSS 的工作是在预解析线程中进行的。这就是 CSS 不会阻塞 HTML 解析的根本原因。- JS 会阻塞 HTML 解析:如果主线程解析到
script位置,会停止解析 HTML,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML。这是因为 JS 代码的执行过程可能会修改当前的 DOM 树,所以 DOM 树的生成必须暂停。这就是 JS 会阻塞 HTML 解析的根本原因。
2. 样式计算 (Recalculate Style)
从 DOM 树变成带样式的 DOM 树。
遍历 DOM 树,依次为每个节点计算它的最终样式。在这一过程中,很多预设值会变成绝对值,比如 red 会变成 rgb(255,0,0);相对单位会变成绝对单位(例如 em 会变成 px)。
3. 布局 (Layout)
带样式的 DOM 树变成布局树,计算元素的位置与几何信息。
4. 分层 (Layer)
产生图层。
主线程会使用一套复杂的策略对整个布局树进行分层。分层的好处在于,将来某一个层改变后,仅会对该层进行后续处理,从而提升效率。
5. 绘制 (Paint)
图层到指令集。
主线程会为每个层单独产生绘制指令集,用于描述这一层的内容该如何画出来。完成绘制后,主线程将每个图层的绘制信息提交给合成线程,此时渲染主线程的当前工作到此结束。
合成线程的工作原理
合成线程接手主线程的任务,将绘制指令转化为真实的像素并输出到屏幕。(阶段 6-8)
6. 分块 (Tiling)
图层到块。
合成线程首先对每个图层进行分块,将其划分为更多的小区域。它会从线程池中拿取多个线程来完成分块工作。
7. 光栅化 (Raster)
块变成位图。
光栅化在 GPU 里面进行,也会开启多个线程,将分好的块转化为实际的像素点(位图)。
8. 画 (Draw)
位图到指引(quad)。
合成线程计算出每个位图在屏幕上的位置,交给 GPU 进行最终呈现,transform 就在这里发生。
面试高频 Q&AQ: 为什么 transform 的效率高? A: 因为
transform既不会影响布局,也不会影响绘制指令,它影响的只是渲染流程的最后一个 Draw 阶段。由于 Draw 阶段在合成线程中执行,所以transform的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌,也不会影响transform的变化。
小结
“将复杂的网页渲染拆解为互相衔接的八个流水线步骤,这正是浏览器工程拆解能力的极致体现。”
通过主线程与合成线程的精妙配合,以及 GPU 的加速渲染,浏览器保障了页面加载时的正确解析,也赋予了页面后续动画与交互的高性能潜力。
部分信息可能已经过时




