浏览器渲染原理

190 阅读4分钟

1.什么是渲染(render)

  1. 浏览器中的渲染是指将 html 字符串转为屏幕上的像素信息的过程
  2. 我们可以将渲染想象成一个render函数,函数接收一个html字符串,将其经过一系列处理得出若干像素点的颜色,将这些像素信息存在 pixels 变量中返回。

2.渲染时间点

当我们在浏览器输入一个URL后,网络线程会通过网络通信拿到html ,但是网络线程本身不会处理html,它会生成一个渲染任务交给消息队列,在合适的时机渲染主线程会冲消息队列中取出渲染任务执行,启动渲染流程

3.渲染流水线

  1. 渲染流水线分为多个阶段:html解析=>样式计算=>布局=>分层=>绘制=>分块=>光栅化=>画=>像素信息
  2. 每一个阶段都有明确的输入和输出,上一个阶段输出会成为下一个阶段的输入

3.1解析html

由于html字符串很难进行操作,浏览器会吧html字符串解析成DOM树CSSOM树这样容易操作的对象结构,也提供几 js操作者两颗树的能力

  1. document就是DOM树的根节点,body是根节点的子节点,只要拿到了根节点将可以能拿到网页的所有节点。
  2. StyleSheetList就是CSSOM的根节点,代表网页中所有的层叠样式表
  3. 层叠样式表有哪些:内部样式表,外部样式表,行内样式,内联样式表,浏览器默认样式表
  4. html解析过程中遇到了cssjs怎么办
    • 遇到了为了提高解析效率,浏览器会启动一个预解析的线程,率先下载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

  1. 主线程会使用一套复杂的策略对整个布局进行分层
  2. 分层的好处在于将来某一层改变了,仅只会对该层进行后续处理,从而提升效率
  3. 滚动条,堆叠上下文,transform等样式都会影响分层,也可以通过 will-change 属性更大程度影响分层结果

3.5绘制

  1. 这里的绘制不是真的绘制而是生成绘制指令
  2. 主线程会为每一层单独产生绘制指令集,用于描述这一层的内容该如何画出来

3.6分块

  1. 完成绘制后,主线程将每一个图层的绘制信息交给合成线程,剩余工作由合成线程完成
  2. 合成线程首先对每一个图层进行分块,划分出更多的小区域
  3. 这个步骤会去线程池中拿出多个线程来共同完成

3.7光栅化

  1. 将上面分好的块进行光栅化变成位图
  2. 合成线程会把处理好了的块信息教给GPU,以极高的速度完成光栅化
  3. GPU进程会开启多个线程来完成光栅化,并优先处理靠近视口区域的块

3.8画

  1. 合成线程把处理好了的块的指令信息给到了GPU。
  2. GPU会根据这些指令信息把每一个位图画到指定的位置,以及会考路道旋转和缩放等变形
  3. 变形是发生在合成线程中,这就是为什么transform快的原因