从chrome火焰图来分析重绘和重排

1,078 阅读4分钟

写在前面


重绘和重排也称重绘和回流(Repaint & Reflow)。我在网上查阅了许多资料基本都是千篇一律,很难将它说清楚,而且还有一些说法是错误的。因此本文将离开纯理论,从实践中来分析到底什么是重绘和重排

先提两个问题


image.png

这里会闪一下吗,如果会,为什么,如果不会,请问怎么能让他闪一下

function appendDataToElement() {
   ele.style.width = '500px';
   // ele.style.transition = 'width 20s';
   document.body.offsetHeight;
   ele.style.width = '2000px';
   // ele.style.transition = 'width 10s';
   document.body.offsetHeight;
   ele.style.transition = 'width 5s';
   ele.style.width = '200px';
}

var ele = document.getElementById('list');

setTimeout(appendDataToElement, 1000)

请问这个元素会怎么运动,如果我将注释代码放开,又会怎么运动

重绘和重排的定义


我谈下我对重绘和重排的理解: 重绘和重排离不开浏览器的event loop,其主要分为任务队列渲染任务,如下图:

f64c1163b51a4fbc822a97fe3888ca0b_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0.webp

主线程不停的从任务队列渲染任务中取出任务执行。其中任务队列渲染任务是互斥的、执行任务队列中的JS任务时是不能执行渲染任务的(这句话是不太准确的,后面会用chrome火焰图来说明)

渲染任务一般就分为3个,图中的S表示Recalculate StyleL表示LayoutP表示Paint。 实际上,通过火焰图发现渲染任务还有两种:Pre-PaintComposite Layers,是否属于渲染任务以及他们的作用,欢迎大家指出。

我们所说的重绘就是SP 两个任务,而重排就是SL,和 P 三个任务。这里我需要说明下:L是依赖于S的,有L任务必须有S任务。而P任务和前面两者不一定是同步的,也就是说可能发生SS和L、而不发生P。如果不发生P,页面就不会刷新,也就不会出现闪烁的效果,就会是一帧。因此我理解的如果不发生P就不算重绘或者重排

到这里,重绘和重排的定义就结束了。下面我们来讨论下上面提出的两个问题:

问题1: 明显不会闪烁,因为JS任务渲染任务互斥,所以永远不会闪烁。至于如果让其闪烁,可以考虑用requestAnimationFrame。另外请大家思考下是否可以用setTimeoutoffsetHeight实现。

问题2比较复杂,我们稍后再分析,先来看看其他文章的说法:

image.png

这是我在掘金上搜到的文章

另外一篇是腾讯大佬写的文章,我也摘了一段分析。

image.png

对于上面两种说法,我都抱有质疑的态度。我的结论是:

任何JS操作都不会触发完整的重绘或者回流,放心大胆的用,除了某些JS操作会触发不完整的重绘或回流。例如offsetWidth某些情况下会触发S任务,某些情况下会触发S和L任务,但是任何JS操作都无法触发P任务,只有依赖浏览器自己去触发。

下面我通过问题2的火焰图来说明:

image.png

可以看到两次offsetHeight都触发了S和L任务、并没有触发P任务,因此最后的动画会从最后一次L任务渐变到最终的形态。也就是宽度从2000px渐变到200px

如果我们打开注释部分代码会怎么样:

image.png

相比于上图,第二次的offsetHeight只触发了S任务,所以会被过滤掉。宽度会从500px渐变到200px

这里我们设置的是会触发L任务的属性,设置只触发S任务的属性也是一样的,只会记录住最后一次触发的状态,渐变到最终的状态。并且,如果我们不设置transition属性,将不会看到任务过渡效果,宽度不会从500px => 2000px => 200px,只会从最初的宽度瞬间到200px,因为我们没有触发paint

因此与其说任务队列渲染任务是互斥的,不如说任务队列P任务是互斥的,JS任务后面可能会穿插S任务或者L任务,但永远不会触发P任务

最后


其实很多代码的效果是无法预测的,因为SL, P三个任务是黑盒,我们只能操作任务队列部分。不过有了火焰图之后,我们就可以分析其中的原理了,也希望大家能熟练掌握火焰图的使用。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。