创作背景:说到浏览器的渲染机制,其实很多博客有讲,但是感觉大家都讲得零零散散,没有太全。所以我就决定根据我在网上搜查到的知识来系统地总结一篇~
- 当浏览器的网络线程收到html文档后,会产生一个渲染任务,并将其传递给渲染主线程的消息队列。在事件循环的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程
渲染流程(在渲染进程中)
1.html解析
-
css的解析为什么不会影响html的解析?
如果主线程解析到link位置,此时外部的css文件还未下载好,主线程不会等待,继续解析后面的html;因为css的解析和下载是在预解析线程中执行的,不在主线程(解析js的进程)
-
js的解析为什么会阻塞html的解析?
如果主线程解析到script位置,会停止解析html,等待js文件下载好,并被v8引擎解析执行完成后,才能继续解析html。因为js代码的执行过程可能会修改当前的DOM树,所以DOM树的生成必须暂停
2.样式计算(主线程)
主线程遍历DOM树,依次为树中的每个节点计算出样式值,即Computed Style。
这一过程中,许多预设值会变为绝对值,例如red->rgb(255,0,0)、相对单位变为绝对单位em->px。
这一步后,会得到一个带有样式的DOM树
3.布局(主线程)
依次遍历DOM树的每一个节点,计算每一个节点的几何信息。例如节点的宽高、相对于包含块的位置。
大部分时候,布局树和DOM树并非一一对应。比如 display:none不会生成在布局树;伪元素不在DOM树,但因为他有几何信息,所以会生成在布局树,等等都会导致两者无法一一对应
最后得到的是布局树(渲染树renderTree)
4.分层(主线程)
主线程使用一套复杂的策略对整个布局树进行分层
好处:某一个层改变后,仅会对该层进行后续处理,从而提升效率
如何分层是浏览器自行执行的,我们不能决定,只能通过设置will-change(css属性)来给建议
5.绘制(主线程)
渲染主线程为各层产生绘制指令,用于描述该层内容怎么画出来
接着将每个图层的绘制信息交给合成线程
6.分块(合成线程)
合成线程从线程池中拿出多个线程进行分块工作
接着将块信息交给GPU进程
7.光栅化(GPU进程)
GPU开启多个线程进行光栅化,并且优先处理靠近视口的块
光栅化的结果是每一块都有它的rgb颜色值
8.画(合成线程、GPU硬件)
合成线程拿到每个层、每个块的具体像素信息后,生成指引
指引:标识每个位图应该画到相对于屏幕的哪个位置,旋转、缩放等变形也在此完成
合成线程将指引交给GPU进程,由GPU进程产生系统调用,提交给GPU硬件,最终完成屏幕成像
完整流程图
好咯~ 如果讲述有错的地方,欢迎各位大佬来指正!