前端性能优化——重绘和回流

一、为什么CSS加载性能会让JavaScript变慢?

​ 在浏览器中,UI渲染和JavaScript的解析实际上是放在两个不同的线程里面进行的,也就是UI的渲染会对应一个线程进行,同时JavaScript的解析会在另一个线程中进行。既然是在两个不同的线程中进行,为什么我们还会说CS加载会影响JavaScript的解析呢?实际上在我们的浏览器中,UI渲染和JavaScript的解析这两个进程之间是一种互斥的关系。这是因为在实际的整个页面渲染和解析中,如果我们的这两个进程同时在进行,可能会使得JavaScript在进行解析的时候,由于DOM并没有完全构建出来,导致js的解析效果并不会像我们预期的那样,也就是这里渲染前和渲染后的效果不一致。因此在真实的浏览器中,一般是在进行css渲染的时候,JavaScript的解析一般是被阻塞的。直到整个css渲染完成之后,JavaScript的代码才会被执行。因此我们可以发现JavaScript的执行时间是取决于css执行的时间的。如果我们频繁的去进行css重绘和回流,就会导致我们频繁的去进行UI渲染进程,这时候js对应的进程就会被阻塞,导致js执行变慢。

二、重绘和回流的定义

回流:当render tree中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建,就成作为回流。一般当页面的布局和几何属性发生变化的时候就需要进行回流。

​ 由此看来,回流对于我们页面的渲染要求较高,可能会影响页面的整体布局,对css渲染的性能影响较大。

重绘:当render tree中的一些元素需要更新属性的时候,而这些属性只是影响元素的外观,风格,而不会影响页面的整体布局和元素的尺寸,比如background。

​ 由上面的定义可知,重绘不一定会引发回流,但是回流一定会触发重绘。

触发页面重布局的因素

  • 盒子模型相关的属性会触发重布局
  • 定位属性以及浮动会触发重布局
  • 改变节点内部文字结构也会触发重布局

###三、避免重绘回流的方法

​ 想要获得更好的前端性能优化和体验势必要在重绘和回流这里进行相关的优化,尤其是在移动端,CPU的运算能力并不是很强,频繁的重绘和回流会造成一些卡顿等问题。所以我们需要在重绘和回流方面做一些优化处理。

​ 在浏览器中,一般新建DOM 的过程主要分为:

  1. 获取DOM后分割为多个图层,这时候的图层会根据我们的一些CSS属性进行一些分割。
  2. 对每个图层的节点计算样式结果。(recalculate style—样式重计算)
  3. 为每个节点生成图形和位置。(layout—回流和重布局)
  4. 将每个节点绘制填充到图层位图中(Paint Setup和Paint—重绘)
  5. 图层作为纹理上传到GPU。
  6. 符合多个图层到页面上生成最后的屏幕图像(Composite Layers—图层重组)

​ 通过这样的一个过程,我们就可以尝试将频繁重绘回流的DOM元素单独作为一个独立的图层,那么这个DOM元素的重绘和回流影响只会在这个图层中,这样就能够减少我们在进行重回回流时候的成本,有效提高css渲染的性能。

​ 在chrome浏览器中,构建一个图层的条件主要是:

  • 3D或者透视变换的css属性
  • 使用加速视频解码的
  • 拥有3D(webGL)上下文或者节点

​ 在实际的开发过程中,我们通常会对经常有变化的一些视频,gif图等区域加上一个图层,主要的目的就是让这些重绘和回流的操作控制在一个图层内从而产生较少的性能消耗。但是在实际的业务中也不能建立太多的图层,这是因为图层的建立过程本身会消耗大量的时间。我们打开一个页面,修改这样一段css代码:

1
2
3
4
5
*{
margin: 0;
padding: 0;
transform: tanslateZ(0);
}

​ 在chrome浏览器中,这样就给所有的元素创建一个图层,然后利用chrome浏览器中的layers功能,明显现在要卡顿很多,同时这时候利用performs会发现,很明显这时候composite Layers的构建占据了大量的时间,这当然是不符合要求的。而且如果图层的数过多,会导致图层优化后的性能反而不及优化前。

四、实战中的相关优化点

1.使用translate代替top

2.使用opacity替换visibility

3.不要一条一条修改DOM样式,而是预先定义好class,然后修改DOM的className,以减少重绘的次数。

4.把DOM离线修改(先display:none)

5.不要把DOM节点的属性放在一个循环里当成循环的变量。

6.不要使用table布局,即使是更改最后一行也会造成所有布局的更新。

7.动画实现的速度选择。

8.对于动画新建图层

9.使用GPU硬件加速(并行运算单元)

0%