浏览器渲染过程
一、解析HTML
解析过程中遇到css
解析css
,遇到JS
执行JS
。为了提高解析效率
,在解析开始时会启动一个预解析
线程,率先下载
html中的外部css
和JS
文件。
如果主线程解析到 link
位置时,主线程不会
等待而是继续执行,因为下载和解析css工作的过程是在预解析
线程中的。这也是css不会阻塞
渲染的根本原因。
如果主线程解析到 script 位置时,会立即执行
script内的所有代码。并且等待
执行完毕。因为script有可能操作dom。这也是JS会阻塞
渲染的原因
该步骤完成后,会得到DOM树与CSSOM树。所有样式都会在CSSOM树中。
二、样式计算
主线程会遍历得到的dom树,依次为每个dom节点计算其的样式。成为computed style。
在这一步骤中,相对单位会变成绝对单位。rm=>px…
最后会得到一颗带样式的DOM树
三、布局
主线程会遍历DOM树,对于每一个节点根据其样式生成几何信息。宽高等。
最终生成一颗布局树。很多时候DOM树与布局树是不一样的。比如display:none的元素、匿名盒子是没有布局的。
四、分层
主线程会经过一系列特殊的策略对布局树进行分层。
分层的好处在于,将来某个层发生变化时,仅对该层进行操作从而提升效率。这也是优化
的一个点之一。
堆叠上下文的样式会影响分层的决策,但是不能决定分层。通过css属性will-change会有更大权重的影响分层。
五、生成绘制指令
主线程对每个图层生成单独的绘制指令集,用于描述这一层的内容如何画出来。
该步骤完成后,主线程不再工作。将会把后续工作交给新线程合成线程
来做。
六、分层
合成线程将对每个图层进行分块,将会启用更多的线程来同时进行分块。
七、光栅化
合成线程将块信息交给GPU进行处理,优先处理靠近视口的块。得到位图信息。
画
合成线程拿到每个层、块的位图信息后,将会生成与块、层一一对应的指引信息。
指引会标识出每个层、块应该画在屏幕的哪个位置,以及考虑缩放旋转等形变。
形变发生在合成线程,不在主线程。这也是为什么tranfrom效率高的原因
最后、合成线程把指引交给浏览器的GPU进程,由浏览器的GPU进程进行GPU硬件调用,完成屏幕绘制。因为渲染进程是个沙盒(被保护起来的,无法与外部直接通信),所以要交给GPU进程进行系统调用。