浏览器渲染原理

245 阅读4分钟

浏览器是如何渲染页面的

当浏览器的网络线程收到 HTML 文档后,会生成一个渲染任务,并将其传递给渲染主线程的消息队列。在事件循环机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。


整个渲染流程分为多个阶段,分别是: HTML 解析、样式计算、布局、分层、绘制、分块、光栅化、画。

image.png

① **解析HTML生成DOM树和CSSOM树 ** parse

为了提高解析效率,浏览器会启动一个预解析线程率先下载和解析外部的css文件,解析完成后,就会交付给浏览器的渲染主线程,生成CSSOM树。所以说,如果渲染主线程解析HTML文档过程中解析到了 link标签,此时css文件没有解析完成,渲染主线程不会等待,它会继续解析后续的HTML。这是因为css的解析工作是在预解析线程中进行的,只有等解析完成后,才会交付给浏览器的渲染主线程。这也就是为什么css不会阻塞html的解析。

HTML解析过程中遇到了js代码

渲染主线程遇到js时必须暂停一切行动,等待js下载执行完后才继续。这是因为js代码执行过程中可能会修改当前DOM树

这一步完成后,就会得到DOM树和CSSOM树

image-20230619110619574

② **样式计算 ** style

生成DOM树后,主线程会遍历 DOM 树并结合CSSOM树,依次为树中的每个节点计算出它最终的样式,比如em会变成 pxred会变成rgb(255,0,0),这一步完成后,会得到一棵带有样式的 DOM 树,称为render树

③**布局 ** layout

渲染树生成后,接下来就是布局,布局阶段会依次遍历 render树(带有样式的DOM树)的每一个节点,计算每个节点的几何信息。例如节点的宽高、相对包含块的位置

大部分时候,DOM树和布局树不是一一对应的。比如display:none的DOM节点并不会作为布局树节点添加到布局树中。

④ **分层 ** layer

主线程会使用一套复杂的策略对整个布局树中进行分层,和堆叠上下文有关的属性如z-index,opacity会影响到分层的结果。分层的好处在于,将来某一个层改变后,仅会对该层进行处理,从而提升效率。

绘制 paint

这里的绘制,是为每一层生成如何绘制的指令用于描述这一层的内容该如何画出来。其实类似于canvas

分块

分块会将每一层分为多个小的区域,将工作交给多个线程同时进行。

光栅化

分块完成后,合成线程会将块信息交给GPU进程进行光栅化即将每个块变成位图,它会优先处理靠近视口的块

合成线程拿到每个块的位图后,生成一个个「指引(quad)」信息。指引会标识出每个位图怎么画。transform就是发生在这里,它与之前的步骤(样式计算,布局,分层绘制指令无关),与渲染主线程无关,只是个矩阵变换,所以效率高

什么是reflow (回流 重排)

reflow 的本质就是重新计算 layout 树,即重新布局。它会影响到后面的分层,绘制,分块,光栅化,画等多个步骤。

当进行了会影响布局树的操作后比如修改了width,padding,height等,需要重新计算布局树,会引发 layout重新布局,继而影响到后面的多个步骤。

为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 reflow 是异步完成的

当 JS 获取布局属性clientWidthoffsetWidth时,就可能造成无法获取到最新的布局信息,因此会立刻reflow。

reflow一定会导致repaint

什么是repaint (重绘)

修改了颜色、透明度等,与几何信息无关的属性,它只需要重新计算样式,无需重新布局,也无需分层,但是需要paint,分块,光栅化和画。

为什么transform效率高

因为transform发生在最后一个draw步骤中,而且与渲染主线程无关,只是个矩阵变化,所以效率高。