浏览器的网络线程拿到静态资源文件后,会生成一个渲染任务,放入消息队列中,渲染线程会将其取出执行对应的渲染任务。
整体的渲染流程
- 解析HTML
- 样式计算
- 布局
- 分层
- 绘制
- 分块
- 光栅化
- 画
1. HTML的解析
总的来说就是就是将HTML文件中的标签和CSS文件中的选择器解析成两棵逻辑树,分别是DOM树和CSSOM树。树中的每一个元素叫做节点,本质上是C++对象,只不过我们可以通过js去操作而已。
DOM树大家还可能比较熟悉,那么这个CSSOM树是怎么回事儿呢?
实际上,每一个标签页实例都会维护一个StyleSheetList,也就是样式表合集。我们可以从图中看到这个网页有73个样式表对象(CSSStyleSheet)。每一个样式表对象下面都有一些属性:
这就是CSSOM树,以StyleSheetList为根节点的多叉树。(CSS Object Model)
(不理解也没关系,我这里难得画图)
HTML解析过程中,遇到CSS代码怎么办?(非阻塞)
为了提高解析效率,浏览器会启动一个预解析器(线程)率先下载和解析(简单)CSS。
HTML解析过程中,遇到JS代码怎么办?(阻塞)
渲染线程遇到JS代码时,会执行JS代码或者等待JS文件资源下载完毕再执行。
2. 样式计算
得到DOM节点的计算后的样式(Computed Style),也就是说,在这一步,DOM对象上会新增一些新属性。
计算后的样式?
每一个样式都会有值:
可以自行去浏览器控制台中查看。
(关于CSS属性的计算过程,我也不是特别清楚,可自行去网上搜索相关文章看一下)
3. 布局
DOM树现在要转成Layout树了。
(这里我也不是很清楚这个过程。。。)
4. 分层 - Layer
可以理解为Photoshop的图层。(当然,我也不是太懂。)
5. 绘制
为每一层生成绘制的指令。
(渲染线程的工作到此结束,剩下的步骤交给其他线程处理)
6. 分块
分块会将每一层分为多个小区域。
分块的工作是交给多个线程同时进行的。
7. 光栅化
块信息会被交给GPU进程,以极高的速度完成光栅化。
CPU进程会开启多个线程来完成光栅化,并且优先处理靠近视口区域的块。
光栅化的结果,就是一块块的位图(每个像素点的颜色)。
8. 画
合成线程拿到每个层、每个块的信息后,生成一个个的【指引(quad)】信息。
指引会标识出每个位图应该被画到哪一个位置,以及优先考虑到旋转、缩放等变形。
变形发生在合成线程,与渲染线程无关,这就是 transform 效率高的本质原因。
合成线程会把quad提交给GPU进程,由GPU进程产生系统调用,提交给GPU硬件,最终在屏幕上输出。
一些经典的问题
什么是reflow?
reflow的本质就是重新计算 layout 树。
当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。
为了避免连续多次操作导致布局树的反复计算,浏览器会合并这些操作,当js代码全部完成后再进行统一计算。所以,改动属性操作的reflow是异步完成的。
也同样因为如此,当js获取布局属性时,就可能造成无法获取到最新的布局信息。
浏览器在反复权衡下,最终决定获取属性立即reflow。
什么是repaint?
repaint的本质就是重新根据分层信息计算了绘制指令。
当改动了可见样式后,就需要重新计算,会引发 repaint。
由于元素的布局信息也属于可见样式,所以 reflow 一定会引起 repaint。
(由于博主并没有深入的研究这方面,所以无法给出很多具体的信息,只能告诉你有这么个东西,如果其中的细节你都能摸清楚的话,那么你对于前端的理解,将迈入一个新高度)
2024.10.23
writeBy kaiven