持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
谈到浏览器渲染过程,无非就是:
- 构建DOM树
- 构建CSSOM树
- 构建渲染树,也就是render Tree
- 布局
- 绘制
但是这其中也包含一些细节的知识,这篇文章就是来尝试着总结一下。
解析
浏览器在渲染页面的时候会解析三样东西:
- HTML
- CSS
- JS
构建DOM树
首先浏览器会从网络请求中或者本地中获得字节数据进行解析(没错最开始获得的是字节数据),然后会将字节数据转换成字符串,字符串也就是我们平时看的懂的代码,之后字符串代码会转换成Token,此时的Token只是描述标签或者说是节点之间的关系等,之后Token转换成节点对象,节点对象相对于Token来说的话,就是节点已经可以编程了,拥有自己的一些属性。然后根据节点之间的关系进行构建DOM,也就是文本对象模型。
在Token转换为节点的时候,有一个tip,构建DOM的时候,不是等待生成了所有的Token才去生成节点对象,而是一边生成Token,一边利用现成的Token去生成节点对象。
构建CSSOM树
构建CSSOM树和构建DOM树的过程是十分相像的。
构建渲染树
构建渲染树就是将DOM树和CSSOM树结合起来,并且渲染树只包含可显示的节点和这些节点的信息。如css属性display:none 的结点是不会包含在渲染树。
补充的小知识:
浏览器包含两个线程,一个是GUI渲染线程,一个是JS引擎线程,因为JS是可以操控DOM和CSS的,所以这两个线程是互斥的。所以说JS的加载,解析和执行都会阻塞DOM的构建,也就是说浏览器在构建DOM的时候,如果遇到JS代码,如script标签就会阻塞DOM的构建。这就是为什么要将script标签放在body标签下边的其中原因之一
这也涉及到了一个性能优化的问题,首屏加载速度,如果想要首屏加载速度加快,首屏所要加载的js文件就要适当的减少。
同时JS代码也会使CSSOM的构建阻塞DOM的构建,没错,就是类似于借刀杀人。JS代码可以操控css,但是CSS由于继承和多种选择器的关系,导致CSS不能部分解析,只能全部解析才能被JS操作。也就是说,如果一段JS代码修改了CSS样式的话,就必须先获得完整的CSSOM,然后执行JS代码,然后在继续构建CSSOM
小结:
- 浏览器有两个线程,GUI渲染线程,JS引擎线程,是互斥的
- JS代码会阻塞DOM树的构建,DOM树和CSSOM树的构建是同步
- JS代码可以使CSSOM树阻塞DOM树的构建。
布局与绘制
布局就是计算渲染树上的结点,在屏幕上的位置,绘制就是将渲染树的内容根据布局进行绘制在电脑屏幕上。
重绘和重排
重绘就是改变了节点的样式属性,会导致重新进行绘制
重排就是改变了节点的几何属性,改变一个节点的几何属性就可能导致多个节点的几何属性一起发生变化(如margin,padding和width等),所以说,一旦重排就会重新计算布局并且重新进行绘制,这样对性能的消耗是巨大的。
重排优化建议
- 样式操作集中处理
- 分离读写操作,可以减少重排和重绘的次数
- 将DOM离线,将display设置为none(一次重排),进行集中的修改样式等,再将display设置回来(一次重排),通过这种方式,即便是有大量的变更,也只有两次重排。visibility:hidden只能影响重绘无法影响重排
- GPU加速,GPU专门负责图像处理的,所以说可以将一些图形操作交给GPU来进行处理。包括以下几个,transitions,transform和canvas等
- 使用绝对定位和固定定位,这样重排的时候,影响其他的节点代价较小。