前端性能-重绘和重排(回流)

前言:

重绘和重排这两个词在面试过程中经常听到,也是老生长谈的话题,为啥它们就这么受我们关注呢,了解它对我们编写代码又有什么好处呢?这里就带大家一起学习下。

页面构建的过程:

  1. HTML 被 HTML 解析器解析成 DOM 树;
  2. CSS 被 CSS 解析器解析成 CSSOM 树;
  3. 结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree);
  4. 生成布局(layout),浏览器在屏幕上“画”出渲染树中的所有节点;
  5. 将布局绘制(paint)在屏幕上,显示出整个页面。

前端性能-重绘和重排(回流)_第1张图片

Reflow (重排):

当涉及到DOM节点的布局属性发生变化时,就会重新计算该属性,浏览器会重新描绘相应的元素,此过程叫回流(Reflow)。

Repaint(重绘):

当影响DOM元素可见性的属性发生变化 (如 color) 时, 浏览器会重新描绘相应的元素, 此过程称为重绘(Repaint)。

注意:重绘不一定导致重排,但重排一定会导致重绘。

重排(reflow):

当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。

重排也叫回流,简单的说就是重新生成布局,重新排列元素。

触发重排的场景:

  • 页面初始渲染,这是开销最大的一次重排;
  • 添加/删除可见的DOM元素;
  • 改变元素位置;
  • 改变元素尺寸,比如边距、填充、边框、宽度和高度等;
  • 改变元素内容,比如文字数量,图片大小等;
  • 改变元素字体大小;
  • 改变浏览器窗口尺寸,比如resize事件发生时;
  • 激活CSS伪类(例如::hover);
  • 设置 style 属性的值,因为通过设置style属性改变结点样式的话(频繁设置属性不会每次都会重排,浏览做了相应的渲染队列优化);
  • 查询某些属性或调用某些计算方法:offsetWidth、offsetHeight等,除此之外,当我们调用 getComputedStyle方法,或者IE里的 currentStyle 时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。(查询属性和调用计算方法每次都会触发重排)

前端性能-重绘和重排(回流)_第2张图片

重排影响的范围:

由于浏览器渲染界面是基于流式布局模型的,所以触发重排时会对周围DOM重新排列,影响的范围有两种:

  • 全局范围:从根节点html开始对整个渲染树进行重新布局;
  • 局部范围:对渲染树的某部分或某一个渲染对象进行重新布局(DOM节点几何信息不曾改变,仅内部进行重排);

重绘(Repaints):

当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。

触发重绘的场景:

  • 设置元素的透明度;
  • 设置元素的背景色,字体颜色;
  • 设置元素的可见性。

常见属性:
前端性能-重绘和重排(回流)_第3张图片

优化建议:

重排的代价是高昂的,会破坏用户体验,并且让UI展示非常迟缓。通过减少重排的负面影响来提高用户体验的最简单方式就是尽可能的减少重排次数,重排范围。

减少重排范围:

当重排无可避免时,尽量避免全局范围的重排,进行局部范围的重排,尽量以局部布局的形式组织html结构,尽可能小的影响重排的范围。

  • 尽可能在低层级的DOM节点上进行修改,避免通过父元素修改改变内部元素。
  • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。

减少重排次数:
  • 样式集中改变,通过更改类名而不是直接修改样式或设置属性。

  • 减少样式改变的次数,过滤修改过程中无必要的操作。

  • 分离读写操作,DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。(这样多个写操作只会触发一次重排)

  • 将 DOM 离线

    1. 使用 display:none,元素便不会再存在在渲染树中,相当于将其从页面上“拿掉”,我们之后的操作将不会触发重排和重绘,添加足够多的变更后,通过 display属性显示(另一次重排重绘),这样多次的重排重绘缩减成两次而已。
    2. 通过 documentFragment 创建一个 dom 碎片,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
    3. 复制节点,在副本上工作,然后替换相应节点。
  • 使用 absolute 或 fixed 布局,使它脱离文档流,避免引起父元素及后续元素大量的回流。

  • 缓存布局信息。

  • 优化动画

    1. 把动画效果应用到 position属性为 absolute 或 fixed 的元素上,这样对其他元素影响较小,其次减少相应动画流畅性,否则Layout就会过于频繁,大量消耗CPU资源。
    2. 启用GPU加速GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。

拓展:

涉及GPU加速的属性: Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。

页面渲染时间解析:

  1. 打开开发者工具:点击 Performance 左侧有个小圆点 点击刷新页面会录制首屏页面加载出来时间的分配情况。
    前端性能-重绘和重排(回流)_第4张图片
  • 蓝色: 网络通信和HTML解析
  • 黄色: JavaScript执行
  • 紫色: 样式计算和布局,即重排
  • 绿色: 重绘
  1. 点击 Event Log:单独勾选 Loading 项会显示 html 和 css 加载时间:
    前端性能-重绘和重排(回流)_第5张图片
  2. 解析完 DOM+CSSOM 之后会生成一个渲染树 Render Tree。
  3. 通过渲染树中在屏幕上“画”出的所有节点,称为渲染。
总结:

重排也是导致DOM脚本执行效率低的关键因素之一,但也是不可避免的,因此我们在开发时,应尽量按照文中的建议来组织代码,这种优化重排与重绘作为大厂经常出现的面试题,并且涉及的性能优化,这是前端必须掌握的基本概念/技能之一。

你可能感兴趣的:(前端性能,前端性能)