浏览器的渲染原理
记录下浏览器渲染相关的一些问题
浏览器时如何渲染页面的?
- 当浏览器的网络线程收到 HTML 文档后,会产生一个渲染任务,并将其传递给主线程的消息队列。
- 在事件循环机制下,渲染主线程从消息队列中取出渲染任务,开启渲染流程。
- 整个流程分为多个阶段,分别是:HTML 解析、样式计算、布局、分层、绘制、分块、光栅化、画出页面。
HTML解析过程中,遇到CSS代码怎么办?
- 为了提高解析效率,浏览器会启动一个预解析器(一个新的线程 )率先下载和解析CSS
解析HTML过程中,遇到CSS 解析 CSS,遇到 JS 执行 JS。浏览器会在预解析线程中去下载外部发css和js文件。
如果主线程解析到Link 标签,此时外部CSS文件还没下载好,主线程不会等待,而是继续解析后续HTML,所以CSS代码不会阻塞解析HTML,因为下载和解析CSS的工作是在预解析线程中 进行的 。
如果主线程解析到 script ,会停止解析HTML,、等待 js 文件下载好,兵将全局代码解析执行完毕后,才继续解析 HTML,因为JS代码的执行过程可能会修改DOM树,所以DOM树的生成必须暂停。这就是JS会阻塞 HTML解析的原因。
浏览器执行步骤
- 解析HTML-Parse HTML:
- 生成 DOM 树 和 CSSOM 树
- 样式计算(Computed style):会得到每个节点的最终样式,这一过程中很多预设值会变成绝对值,比如 red会变成 rgb(255, 0, 0),相对单位会变成绝对单位,比如 em 会变成 px。最终得到一个带有样式的DOM树
- 布局(Layout):根据上一步生产的DOM树,生成 layout树。(DOM树和Layout树不一定是一一对应的。内容必须放在行盒里面,块盒和行盒不能相邻)display:none的节点没有几何信息不会产生布局树;使用了伪元素,虽然DOM树中不存在这些伪元素节点,但它们拥有几何信息,会生成到布局树中,所以可能会导致不对应
- 分层(Layer): 主线程会使用一套复杂的策略队整个布局树进行分层。分层的好处在于,将来某一个层改变后,仅会对该层进行后续处理,从而提高效率。滚动条、堆叠上下文、transform、opacity等样式会影响分层结果,也可以通过will-change属性更大程度的影响分层结果。
- 绘制(paint):这里的绘制,是为每一层生成如何绘制的指令。 到这一步,渲染主线程的工作到此为止,剩余步骤交给其他线程(合成线程,也是渲染进程中的一个子线程)。
- 分块-Tiling:将每一层分成多个小的区域。
- 光栅化- Raster(GPU进程中进行) :光栅化是将每个块变成位图,优先处理靠近视口的块。此过程会用到GPU加速。
- 画-Draw :合成线程计算出每个位图在屏幕上的位置,交给GPU最终呈现
其他
reflow(回流):本质是重新计算 layout树
repaint(重绘):本质是重新根据分层信息计算绘制指令
reflow一定会repaint。
为什么transform效率高?
- 因为transform既不影响布局,也不影响绘制指令,它影响的只是渲染流程的最后一个【draw】阶段。因为draw在合成线程中,所以transform几乎不会影响渲染主线程。反之,渲染主线程多繁忙也不会影响transform的变化。
感谢你的阅读。