重绘和回流以及如何优化

1、浏览器渲染机制

浏览器采用流式布局模型(Flow Based Layout)
浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了渲染树(Render Tree)。
有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。
由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。

重绘和回流以及如何优化

为了构建渲染树,浏览器主要完成了以下工作:
从DOM树的根节点开始遍历每个可见节点。
对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。
根据每个可见节点以及其对应的样式,组合生成渲染树。
第一步中,既然说到了要遍历可见的节点,那么我们得先知道,什么节点是不可见的。不可见的节点包括:
一些不会渲染输出的节点,比如script、meta、link等。
一些通过css进行隐藏的节点。比如display:none。注意,利用visibility和opacity隐藏的节点,还是会显示在渲染树上的。只有display:none的节点才不会显示在渲染树上。
注意:渲染树只包含可见的节点.

2、回流 (refolw)

节点的几何属性或者布局发生改变被称为回流,一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流,所以一个节点的回流会引起页面某个部分甚至整个页面的回流。

3、重绘(repaint)

节点的样式改变且不影响布局的,比如color,visibility等,称为重绘。

** 重绘不一定回流,回流一定重绘。 **

4、 浏览器优化

现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。
主要包括以下属性或方法:
offsetTop、offsetLeft、offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
getComputedStyle()
getBoundingClientRect

所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。
这里我有思考一个问题,为什么强制清空浏览器UI渲染队列会引起性能问题?
参考这篇文章 《https://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%e5%8a%a8%e7%94%bb%e7%ae%97%e6%b3%95/》 说说FPS的东西。

重绘和回流以及如何优化

相当一部分的浏览器的显示频率是16.7ms, 就是上图第一行的节奏,表现就是“我和你一步两步三步四步往前走……”。如果我们火力搞猛一点,例如搞个10ms setTimeout,就会是下面一行的模样——每第三个图形都无法绘制(红色箭头指示),表现就是“我和你一步两步 坑 四步往前走……”。
国庆北京高速,最多每16.7s通过一辆车,结果,突然插入一批setTimeout的军车,强行要10s通过。显然,这是超负荷的,要想顺利进行,只能让第三辆车直接消失(正如显示绘制第三帧的丢失)。然,这是不现实的,于是就有了会堵车!
同样的,显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题。不仅如此,这种计时器频率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。(这里是原文)
我比较认同下面这个观点
‘setTimeout为10ms,为什么我感觉应该丢失的是第二帧,第一帧10ms后进行绘制,此时浏览器刚开始进行渲染。然后过10ms,此时还没达到浏览器的显示频率是16.7ms,所以第二帧丢失,再过10ms,距离第一次绘制已经过去20ms了大于16.7ms,所以第三帧可以绘制。
上面这点歧义也只是计算上有点问题,但是问题原作者已经给我们解释得很清楚了。
过度绘制带来的问题一是会出现掉帧的情况(丢失某一时间点的动画)造成卡顿,二是大量的UI渲染任务聚集在后面会导致电池寿命及其他应用的性能。
而强制清空浏览器UI渲染队列会引起大量的UI渲染任务聚集在一次EventLoop中(同步中)去完成,自然会导致上面第二点,大量的UI渲染任务聚集在后面会导致电池寿命及其他应用的性能。

5、减少回流和重绘 5.1、批量修改DOM或者样式

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspzxg.html