浏览器渲染原理

浏览器是如何渲染页面的

当浏览器的网络线程收到HTML文档后,会产生一个渲染任务,并将其传递给渲染主线程的消息队列

在事件循环过程中,渲染主线程取出队列中的渲染任务,开启渲染流程

渲染流程

浏览器渲染流程.png

1、解析HTML----Parse HTML

解析过程中,遇到CSS解析CSS,遇到JS执行JS,为了提高效率,开始解析前,浏览器会启动一个预解析线程去下载外部的CSS文件和JS文件

主线程解析到link时,如果此时的CSS文件还没有下载解析完成,主线程不会等待,继续解析后面的HTML,所以css不会阻塞HTML解析

主线程解析到script,主线程会停下来,直到这个js被下载并将全局代码解析执行完成后,主线程才会继续解析,这是因为js代码可以对DOM进行修改,必须暂停DOM树的生成,这就是为什么js会阻塞HTML解析的原因

这一步完成后,会生成DOM树和CSSOM树,内部样式、内联样式、外部样式、浏览器的默认样式都会包含在CSSOM树中

image.png

2、样式计算----style

主线程遍历DOM树,依此为每个节点计算最终样式(Computed Style)

在这个过程中,会将预设值转为绝对值,red->rgb(255,0,0),相对单位转为绝对单位em->px

这一步完成后,会生成一颗带Computed Style的DOM树

image.png

3、布局----layout

主线程依此遍历DOM的每一个节点,计算每一个节点的几何信息,比如节点的宽高、相对包含块的位置

很多时候,layout树和DOM树不是一一对应的

比如display:none的节点没有几何信息,所以不会生成到layout树,DOM上不存在伪元素节点,但是它们拥有几何信息,所以会生成到layout树

image.png

4、分层----layer

主线程将布局树进行分层

将来某一层发生变动后,只需要对该层进行处理,提高了效率

滚动条、堆叠上下文、transform、opacity 等样式都会或多或少的影响分层结果,也可以通过will-change属性更大程度的影响分层结果

在控制台可以查看到当前页面的分层信息

截屏2023-06-14 18.26.41.png

5、绘制----paint

主线程会为每一层生成绘制指令集,描述这一层该如何画出来

完成绘制后,渲染主线程将每层的绘制信息交给合成线程

6、分块----tiling

合成线程将每一层进行分块,分为多个更小的区域,多个线程完成分块工作

7、光栅化----raster

合成线程在分块后,将分块信息交给GPU进程进行光栅化

GPU 进程会开启多个线程来完成光栅化,并且优先处理靠近视口区域的块。

光栅化的结果,就是一块一块的位图

8、画----draw

合成线程拿到每个层、每个块的位图后,生成一个个「指引(quad)」信息。

指引会标识出每个位图应该画到屏幕的哪个位置,以及会考虑到旋转、缩放等变形。

变形发生在合成线程,与渲染主线程无关,这就是transform效率高的本质原因。

合成线程会把 quad 提交给 GPU 进程,由 GPU 进程产生系统调用,提交给 GPU 硬件,完成最终的屏幕成像

重排(reflow)

reflow的本质是重新计算layout树

如果进行了影响布局树的操作后,就得重新计算布局树,会引发layout,为了避免连续的操作导致布局树反复计算,浏览器会合并操作,当js代码完成后在统一进行计算,所以改动属性造成的reflow是异步完成的,正因如此,在修改后去获取布局属性,拿到的可能不是最新的值,浏览器在反复权衡下,最终决定获取属性立即reflow

重绘(repaint)

repaint的本质是重新计算分层信息生成绘制指令集

当改动了可见样式后,需要重新计算,会引发repaint 由于元素的布局信息也属于可见样式,所以reflow一定会引起repaint

为什么transform效率高

transform不会影响布局也不会影响绘制指令,他影响的只是渲染流程的最后一个draw阶段,draw阶段运行在合成线程中,不会影响到主线程,反之,渲染主线程很忙碌,也不会影响到transform的变化

如何减少重排重绘

  1. 使用 CSS 动画代替 JavaScript 动画:CSS 动画可以使用浏览器的硬件加速,性能更好。相比之下,使用 JavaScript 实现的动画通常需要在每一帧重新计算样式和布局,会引起较多的重排和重绘。
  2. 避免频繁操作样式:在 JavaScript 中频繁修改元素的样式会导致多次重排和重绘。为了减少这种情况,可以将需要修改的样式属性合并到一个 CSS 类中,然后通过添加或移除类名的方式来改变样式。
  3. 使用 transform 属性:transform 属性可以对元素进行位移、缩放、旋转等变换,而不会引起重排和重绘。通过使用 transform,可以更好地优化动画效果。
  4. 使用 DocumentFragment:当需要向页面中添加大量的 DOM 元素时,可以使用 DocumentFragment。DocumentFragment 是一个轻量级的文档片段,可以在其中构建 DOM 结构,然后一次性将其添加到页面中,这样可以减少重排的次数。
  5. 避免强制同步布局:有些属性或方法会导致强制同步布局,比如读取元素的尺寸或位置信息(比如 offsetTop、offsetWidth 等)。在可能的情况下,避免频繁使用这些属性或方法,或者将它们的使用集中在一起,以减少重排的次数。
  6. 分离读和写操作:尽量将读操作和写操作分离开来。先进行所有的写操作,然后再进行读操作,这样可以最大程度地减少重排的次数。
全部评论

相关推荐

07-02 10:39
门头沟学院 Java
Steven267:说点真实的,都要秋招了,还没有实习,早干嘛去了,本来学历就差,现在知道急了,而且你这个简历完全可以写成一页,劣势太大了,建议转测试
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务