1.什么是渲染(render)
- 浏览器中的渲染是指将 html 字符串转为屏幕上的像素信息的过程
- 我们可以将渲染想象成一个render函数,函数接收一个html字符串,将其经过一系列处理得出若干像素点的颜色,将这些像素信息存在 pixels 变量中返回。
2.渲染时间点
当我们在浏览器输入一个URL后,网络线程会通过网络通信拿到html ,但是网络线程本身不会处理html,它会生成一个渲染任务交给消息队列,在合适的时机渲染主线程会冲消息队列中取出渲染任务执行,启动渲染流程
3.渲染流水线
- 渲染流水线分为多个阶段:html解析=>样式计算=>布局=>分层=>绘制=>分块=>光栅化=>画=>像素信息
- 每一个阶段都有明确的输入和输出,上一个阶段输出会成为下一个阶段的输入
3.1解析html
由于html字符串很难进行操作,浏览器会吧html字符串解析成DOM树和CSSOM树这样容易操作的对象结构,也提供几 js操作者两颗树的能力
- document就是DOM树的根节点,body是根节点的子节点,只要拿到了根节点将可以能拿到网页的所有节点。
- StyleSheetList就是CSSOM的根节点,代表网页中所有的层叠样式表
- 层叠样式表有哪些:内部样式表,外部样式表,行内样式,内联样式表,浏览器默认样式表
- html解析过程中遇到了css 和js怎么办
- 遇到了为了提高解析效率,浏览器会启动一个预解析的线程,率先下载html中的外部css文件和js文件
- 如果在解析的主线程中遇到了link位置的时候,如果此时外部的css文件还没有下载解析好的话,主线程是不等待的,会继续解析后续的html。这是因为下载和解析css的工作是在预解析线程中进行的,这就是css为什么不会阻塞html解析的根本原因
- 如果主线程解析到了script位置,会停止解析HTML,转而等待js文件下载好,并将全局代码解析执行完后,才继续解析html。这是因为js代码在执行的过程可能修改当前饿DOM树结构,所以DOM树的生成必须暂停,这就是js会阻塞HTML解析的根本原因
- 上面的都完成会得到一颗DOM树和CSSOM树,浏览器的默认样式,内部样式,外部样式,行内样式均会包含在CSSOM树中
3.2样式计算
经过HTML解析后,得到的DOM树和CSSOM树还是不够的,还要知道DOM树对应样式是什么。主线程会遍历得到的DOM树,依次为树中的每一个节点计算出他的最终样式,我们把这个过程称之为Computed Style。在这个计算的过程中很多值都会变成绝对值,相对单位也会变成绝对单位(rem=>px)。 经过上面的步骤我门就会得到一颗带有样式的DOM树
3.3布局
在布局阶段,会计算每一个节点的集合信息,例如宽高和相对包含块的位置 大部分的时候DOM树和布局树不是一一对应的 如何display:none 的节点有DOM树但是 布局树上面是不需要有的
3.4分层 layer
- 主线程会使用一套复杂的策略对整个布局进行分层
- 分层的好处在于将来某一层改变了,仅只会对该层进行后续处理,从而提升效率
- 滚动条,堆叠上下文,transform等样式都会影响分层,也可以通过 will-change 属性更大程度影响分层结果
3.5绘制
- 这里的绘制不是真的绘制而是生成绘制指令
- 主线程会为每一层单独产生绘制指令集,用于描述这一层的内容该如何画出来
3.6分块
- 完成绘制后,主线程将每一个图层的绘制信息交给合成线程,剩余工作由合成线程完成
- 合成线程首先对每一个图层进行分块,划分出更多的小区域
- 这个步骤会去线程池中拿出多个线程来共同完成
3.7光栅化
- 将上面分好的块进行光栅化变成位图
- 合成线程会把处理好了的块信息教给GPU,以极高的速度完成光栅化
- GPU进程会开启多个线程来完成光栅化,并优先处理靠近视口区域的块
3.8画
- 合成线程把处理好了的块的指令信息给到了GPU。
- GPU会根据这些指令信息把每一个位图画到指定的位置,以及会考路道旋转和缩放等变形
- 变形是发生在合成线程中,这就是为什么transform快的原因