浏览器页面渲染流程
渲染模块
HTML、CSS、JS数据通过渲染模块的处理最终输出为屏幕上的像素
渲染流水线
渲染模块被划分为很多子阶段,输入的数据通过这些子阶段最后输出像素,这样的一个处理流程叫做渲染流水线
注意:每个子阶段都有其输入内容、处理过程和输出内容
1.构建DOM树
因为浏览器无法直接理解和使用HTML,所以需要将HTML转换为浏览器能够理解的DOM树结构,生成DOM树
2.样式计算
- 纯文本CSS -> CSSOM结构
浏览器无法直接理解纯文本的CSS样式,渲染引擎会将其转化为浏览器可以理解的CSSOM结构,即styleSheets
样式表
该结构具备查询和修改等操作功能,JS中用document.styleSheets
访问 - 标准化styleSheets样式表中的属性值
将样式表中所有属性的值转换为渲染引擎容易理解的、标准化的计算值 - 计算DOM树中每个节点的具体样式
计算过程遵守CSS的继承和层叠规则,结果被保存在ComputedStyle
结构内
3.布局阶段
计算DOM树中可见元素的几何位置
- 创建布局树
遍历DOM树中所有可见节点并加到布局树中,不可见节点全都忽略 - 布局计算
计算布局树节点的坐标位置,布局运算结果会重新写回布局树中
注意:该子阶段布局树既是输入内容也是输出内容
4.分层
渲染引擎为特定的节点生成专用的图层,并生成一棵对应的图层树。浏览器的页面被分成很多图层,这些图层叠加后合成了最终的页面
注意:不是布局树的每个节点都包含一个图层,如果一个节点没有对应图层则这个节点就从属于父节点的图层
- 元素被提升为一个单独图层的条件
- 拥有层叠上下文属性,如
z-index
,明确定位属性、透明度等 - 需要剪裁的元素
- 如果出现滚动条,滚动条也会被提升为单独的层
- 拥有层叠上下文属性,如
5.图层绘制
渲染引擎会把一个图层的绘制拆分成很多小的绘制指令,然后把这些指令按照顺序组成一个待绘制列表。每个元素的背景、前景、边框都需要单独的指令去绘制
6.分块
渲染主线程把绘制列表提交给合成线程,合成线程将图层划分为图块
- 分块原因
通常一个页面很大,用户只能看到其中一个部分,即视口。绘制所有图层会产生太大开销,没有必要
7.光栅化
合成线程将图块转换为位图。合成线程按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的
- 光栅化线程池
图块是栅格化执行的最小单位,渲染进程维护了一个栅格化的线程池,所有图块的栅格化都是在线程池内执行 - GPU加速
通常栅格化过程都会使用GPU来加速生成,使用GPU生成位图的过程叫快速栅格化或GPU栅格化,生成的位图被保存在GPU内存中
GPU操作是运行在GPU进程中的,所以这涉及到跨进程操作
8.合成和显示
- 所有图块光栅化完成,合成线程会生成一个绘制图块的命令,然后将命令提交给浏览器进程
- 浏览器进程中的viz组件接收到命令后根据命令将页面内容绘制到内存中,最后再将内存显示在屏幕上
渲染流水线中CSS和JS的加载
若在HTML文件中引入CSS和JS文件,还要对它们进行下载和加载
只有CSS
- 首先发起加载主页面的请求,发起请求的可能是渲染进程或浏览器主进程,发起的请求被送到网络进程中去执行
- 网络进程收到返回的HTML数据后将其发送给渲染进程,渲染进程会解析HTML数据并构建DOM树
- DOM树构建结束后向网络进程发起请求CSS文件
- 网络进程收到返回的CSS数据后将其发送给渲染进程,渲染进程收到后将其解析成CSSOM并构建布局树
注意:请求HTML数据和构建DOM中间有一段空闲时间,可能成为页面渲染的瓶颈
CSS+JS
若在两个div中间插入JS脚本,渲染进程中也要加载JS文件
在接收到HTML数据后的预解析过程中,HTML预解析器识别出来了有CSS文件和JS文件需要下载,然后同时发起这两个文件的下载请求
两个文件的下载过程是重叠的,所以下载时间按照最久的文件来算
影响页面展示的因素
渲染流水线影响到首次页面展示的速度,而首次页面展示的速度直接影响到了用户体验
- 从发起URL到首次显示页面视觉上经历的三个阶段
- 第一阶段:发出请求后到提交数据,此阶段页面展示出来的还是之前页面的内容
- 第二阶段:提交数据后渲染进程会创建一个空白页面,这段时间称为解析白屏,等待CSS文件和JS文件的加载完成,生成CSSOM和DOM,然后合成布局树,最后还要经过一系列步骤准备首次渲染
- 第三阶段:等首次渲染完成后就开始进入完整页面的生成节点,然后页面会被绘制出来
- 影响因素
- 影响第一个阶段的因素主要是网络或服务器
- 第二、三个阶段的主要问题是白屏时间,通常瓶颈主要体现在下载CSS和JS文件以及执行JS
- 缩短白屏时间策略
- 内联JS和CSS来移除这两种文件的下载
- 若场景不适合内联,可以尽量减小文件大小
- 将不需要在解析HTML阶段使用的JS标记上
sync
或defer
- 对于大的CSS文件可以通过媒体查询属性,将其拆分为多个不同用途的CSS文件,这样只有在特定的场景下才会加载特定的CSS文件
相关概念
重排(回流)
如果修改元素的几何位置属性,浏览器会触发重新布局,重新执行渲染流水线步骤3~8进行重排
重排需要更新完整的渲染流水线,开销最大
重绘
如果修改元素的绘制属性,浏览器直接进入绘制阶段,重新执行渲染流水线步骤5~8进行重绘
重绘省去布局和分层阶段,执行效率比重排操作高
直接合成
直接执行渲染流水线步骤8,不需要布局和绘制
使用CSS的transform
来实现动画效果,就是直接在非主线程上执行合成动画操作,没有占用主线程的资源,合成大大提升了绘制效率
来源于:极客时间《浏览器工作原理与实践》