web性能优化之减少重排、重绘

188 阅读3分钟

概念解析

Xnip2022-09-27_21-18-44.jpg 页面渲染的流程如上,更多内容可了解chrome渲染流程

DOM结构或者DOM的样式修改可能会引起页面再次执行上述部分流程。

重排

DOM的几何信息(位置和尺寸大小)发生改变,需要重新计算DOM的几何信息,再将其绘制出来的过程叫重排(Relayout),也叫回流(Reflow)
比如widthpositionfloat

重绘

DOM的外观发生变化但没有改变布局,重新把外观绘制出来的过程叫重绘(Repaint)
比如background-colorcoloropacity

可在工具中查看到重排、重绘的时间

Xnip2022-09-29_09-41-48.jpg

重排、重绘对页面性能的影响

流程

从概念中我们知道:
DOM重排,则会触发重新生成布局树(Layout)及其之后的操作。
DOM重绘,则会触发重新绘制(Paint)及其之后的操作。和重排相比,少了布局和分层两个阶段。

以上可知,重排和重绘会让渲染进程、GPU进程、浏览器主进程再次工作,占用资源(主要是渲染进程的CPU计算)。其中,重排的的开销更大。

Demo

以重排为例,来看一下DOM更新的开销

Demo1: 多次访问 + 多次修改

<style>
    #container{
        word-break: break-word;
    }
</style>
<div id="container"></div>
<script>
let times = 20000;
console.time(1);
for(let i = 0; i < times; i++){
    const node = document.getElementById('container');
    node.innerHTML += i;
}
console.timeEnd(1);
</script>

Xnip2022-09-28_20-17-51.jpg 结果 1: 5904.803955078125 ms

多次修改DOM的innerHTML,内容增多,短时间多次重排,需要(相对)长时间使用渲染进程(CPU计算完成后再生成图片)。在图片合成前,页面显示空白。

Xnip2022-09-28_20-57-39.jpg 2.4 对应的是CPU列,页面渲染完成后,又会变成0。
GCP进程的CPU在这过程中也会增大然后又减小。

Demo2: 多次访问 + 一次修改

<script>
    let times = 20000;
    console.time(2);
    let content = '';
    let node = null;
    for(let i = 0; i < times; i++){
        node = document.getElementById('container');
        content += i;
    }
    node.innerHTML = content;
    console.timeEnd(2);
</script>

结果 2: 8.8330078125 ms (每次都不一样,最大没超过17ms)。
从以上两个demo可知,减少重排的次数能明显减少渲染进程执行时间(script在渲染进程中执行)。

Demo3: 一次访问 + 一次修改

<script>
    let times = 20000;
    console.time(3);
    const node = document.getElementById('container');
    let content = '';
    for(let i = 0; i < times; i++){
        content += i;
    }
    console.timeEnd(3);
</script>

结果 3: 1.93896484375 ms (最大没超过9,多数是1、2左右)。
获取DOM也是有消耗的,如果后续还要用到,可以获取一次,保存在内存中。

减少重排、重绘的方法

  1. 如果要改多个属性,一起设置而不是单个多次修改
    比如可以用class或者dom.style.cssText=xx,而不是多个dom.style.xx=xx

  2. 合理利用特殊样式属性,将重排改成合成(见后文)或减少对其他元素的布局影响
    如果节点有动画,可以考虑用用translateY代替height,或者给元素加上position: absloute|fixed

  3. 使用框架
    框架用的虚拟DOM,会先计算出所有变化,然后再进行渲染。

其他

有什么属性修改后既不会改变几何信息也不会改变外观信息的吗?

有,CSS的tranform属性,这类属性变更后重新绘制的过程叫合成
DOM合成,则会触发栅格化及其之后的操作。和重排和重绘相比,此过程绘制步骤更少,且不使用渲染进程的主线程,效率更高。

参考文章