🔥浏览器到底如何渲染出页面的?我想让你知道!!!

872 阅读5分钟

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


浏览器解析渲染页面

流程简述

浏览器内核拿到内容后,渲染步骤大致可以分为以下几步:

  1. 解析HTML,构建DOM树

  2. 解析CSS,生成CSS规则树

  3. 合并DOM树和CSS规则,生成render树

  4. 布局render树(Layout/reflow),负责各元素尺寸、位置的计算

  5. 绘制render(渲染)树(paint),绘制页面像素信息

  6. 浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上

OS:-- reflow:也称作layout,中文叫回流/重排一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树,这个过程称为reflow。

repaint:中文重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如:背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就可以了。


流程详解

1.根据 HTML 解析 DOM 树
  • 根据 HTML 的内容,将标签按照结构解析成为 DOM 树,DOM 树解析的过程是一个深度优先遍历。即先构建当前节点的所有子节点,再构建下一个兄弟节点。
  • 在读取 HTML 文档,构建 DOM 树的过程中,若遇到 script 标签,则 DOM 树的构建会暂停,直至脚本执行完毕。
2.根据 CSS 解析生成 CSS 规则树
  • 解析 CSS 规则树时 js 执行将暂停,直至 CSS 规则树就绪
  • 浏览器在 CSS 规则树生成之前不会进行渲染
3.结合 DOM 树和 CSS 规则树,生成渲染树
  • DOM 树和 CSS 规则树全部准备好了以后,浏览器才会开始构建渲染树
  • 精简 CSS 并可以加快 CSS 规则树的构建,从而加快页面相应速度。
4.根据渲染树计算每一个节点的信息(布局)
  • 布局:通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸
  • 回流:在布局完成后,发现了某个部分发生了变化影响了布局,那就需要倒回去重新渲染。
5.根据计算好的信息绘制页面
  • 绘制阶段,系统会遍历呈现树,并调用呈现器的“paint”方法,将呈现器的内容显示在屏幕上。
  • 重绘:某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的重绘。
  • 回流:某个元素的尺寸发生了变化,则需重新计算渲染树,重新渲染。

img


思考:如何减少回流和重绘?

我们都知道: Reflow要比Repaint更花费时间,也就更影响性能。要尽量避免过多的Reflow。那该怎么来解决呢?

我们首先来回顾一下渲染流水线的流程:

img

想要尽量减少回流和重绘的次数,提高性能,首先我们得先知道触发条件

常见的触发回流的情况:

  1. 一个 DOM 元素的几何属性变化,常见的几何属性有widthheightpaddingmarginlefttopborder 等等, 这个很好理解。
  2. 使 DOM 节点发生增减或者移动
  3. 读写 offset族、scroll族和client族属性的时候,浏览器为了获取这些值,需要进行回流操作。
  4. 调用 window.getComputedStyle 方法。

现在我们来看看回流过程。

依照上面的渲染流水线,触发回流的时候,如果 DOM 结构发生改变,则重新渲染 DOM 树,然后将后面的流程(包括主线程之外的任务)全部走一遍。

img

相当于将解析和合成的过程重新又走了一遍,开销是非常大的。


常见的触发重绘的情况:

当 DOM 的修改导致了样式的变化,并且没有影响几何属性的时候,会导致重绘(repaint)。

重绘过程:由于没有导致 DOM 几何属性的变化,因此元素的位置信息不需要更新,从而省去布局的过程。流程如下:

img

跳过了生成布局树建图层树的阶段,直接生成绘制列表,然后继续进行分块、生成位图等后面一系列操作。

所以说:重绘不一定导致回流,但回流一定发生了重绘


知道上面的原理之后,对于开发过程有什么指导意义呢?

  1. 避免频繁使用 style,而是采用修改class的方式。
  2. 使用createDocumentFragment进行批量的 DOM 操作。
  3. 对于 resize、scroll 等进行防抖/节流处理。
  4. 添加 will-change: tranform ,让渲染引擎为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。当然这个变化不限于tranform, 任何可以实现合成效果的 CSS 属性都能用will-change来声明。

PS:想要了解更多关于回流和重绘,可以看我这一篇文章 🔥什么是重绘和重排? 如何去避免?


感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤