蓝戒的博客


页面重绘(Repaint)、重排(Reflow) 的性能调优解析

理解什么是重绘和重排?
1、重绘(Repaint)
重绘(repaint或redraw):当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。

重绘不会带来重新布局,所以并不一定伴随重排。

"重绘"不一定需要"重排",比如改变某个网页元素的颜色,就只会触发"重绘",不会触发"重排",因为布局没有改变。
但是,"重排"必然导致"重绘",比如改变一个网页元素的位置,就会同时触发"重排"和"重绘",因为布局改变了。

2、重排(Reflow)
重排(重构/回流/reflow):当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
渲染对象在创建完成并添加到渲染树时,并不包含位置和大小信息。计算这些值的过程就称为布局或重排。

Reflow 的成本比 Repaint 的成本高得多的多。DOM Tree 里的每个结点都会有 reflow 方法,
一个结点的 reflow 很有可能导致子结点,甚至父点以及同级结点的 reflow。在一些高性能的电脑上也许还没什么,
但是如果 reflow 发生在手机上,那么这个过程是消耗内存性能和耗电的。

浏览器运行机制
1、构建DOM树(parse):渲染引擎解析HTML文档,首先将标签转换成DOM树中的DOM node(包括js生成的标签)生成内容树(Content Tree/DOM Tree);
2、构建渲染树(construct):解析对应的CSS样式文件信息(包括js生成的样式和外部css文件),而这些文件信息以及HTML中可见的指令(如<b></b>),构建渲染树(Rendering Tree/Frame Tree);
3、布局渲染树(reflow/layout):从根节点递归调用,计算每一个元素的大小、位置等,给出每个节点所应该在屏幕上出现的精确坐标;
4、绘制渲染树(paint/repaint):遍历渲染树,使用UI后端层来绘制每个节点。

重排必定会引发重绘,但重绘不一定会引发重排。

触发重排的条件:
任何页面布局和几何属性的改变都会触发重排,比如:

1、页面渲染初始化;(无法避免)
2、添加或删除可见的DOM元素;
3、元素位置的改变,或者使用动画;
4、元素尺寸的改变——大小,外边距,边框;
5、浏览器窗口尺寸的变化(resize事件发生时);
6、填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变;
7、读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )

重绘发生的情况:

重绘发生在元素的可见的外观被改变,但并没有影响到布局的时候。比如,仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)

渲染树变化的排队和刷新:
当你请求向浏览器请求一些 style信息的时候,就会让浏览器flush队列,比如:
(1)offsetTop, offsetLeft, offsetWidth, offsetHeight
(2)scrollTop/Left/Width/Height
(3)clientTop/Left/Width/Height
(4)width,height

当你请求上面的一些属性的时候,浏览器为了给你最精确的值,需要flush队列,
因为队列中可能会有影响到这些值的操作。即使你获取元素的布局和样式信息跟最近的布局信息差不多,
浏览器都会强行刷新渲染队列。

频繁的重绘重排的代价:耗时,导致浏览器卡慢。

优化:
1、浏览器自己的优化:浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。

2、优化注意:

我们要减少重绘和重排就是要减少对渲染树的操作,则我们可以合并多次的DOM和样式的修改。并减少对style样式的请求。

(1)直接改变元素的className;
(2)display:none;先设置元素为display:none;然后进行页面布局等操作;设置完成后将
元素设置为display:block;这样的话就只引发两次重绘和重排;
(3)不要经常访问浏览器的flush队列属性;如果一定要访问,可以利用缓存。将访问的值存储起来,接下来使用就不会再引发回流;
(4)使用cloneNode(true 或者 false) 和 replaceChild 技术,引发一次回流和重绘;
(5)将需要多次重排的元素,position属性。
设为absolute或fixed,元素脱离了文档流,它的变化不会影响到其他元素;
(6)如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document;

(7)尽量不要使用table布局。

参考资料:

1. https://blog.csdn.net/sophia_little/article/details/79613990

2. https://www.cnblogs.com/zichi/p/4720000.html

本文固定链接: http://www.webzsky.com/?p=1321 | 蓝戒的博客

cywcd
该日志由 cywcd 于2018年11月01日发表在 javascript 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 页面重绘(Repaint)、重排(Reflow) 的性能调优解析 | 蓝戒的博客
关键字: , , ,

页面重绘(Repaint)、重排(Reflow) 的性能调优解析:等您坐沙发呢!

发表评论


快捷键:Ctrl+Enter
来自的朋友,欢迎您 点击这里 订阅我的博客 o(∩_∩)o~~~
×