为什么要避免大量的重绘和重排

重排是指元素的位置、尺寸等几何属性发生变化,需要重新计算页面布局的过程。在某些情况下,如窗口大小改变、DOM元素的增删改等,都可能导致重排。重排会重新计算整个页面的布局,因此性能影响较大。
重绘是指元素的几何属性不变,页面的外观发生变化,重新绘制,但不影响布局的情况,例如改变元素的颜色、背景色等。重绘不会带来重新计算布局的开销,因此性能影响相对较小。但是,如果重绘操作频繁发生,也会对性能产生影响。

当我们改变一个尺寸位置属性时,会重新进行样式计算,布局,绘制,以及后面的所有流程。这种行为我们称为重排。当我们改变某个元素的颜色属性时,不会重新触发布局,但还是触发会样式计算和绘制,这个就是重绘。我们可以发现重排和重绘会占用主线程,JS的运行也是在主线程。既然他们都是在主线程就会出现抢占执行时间的问题。
如果我们写了个不断导致重绘重排的动画,浏览器则需要在每一帧都会运行样式计算、布局和绘制的操作,我们知道当页面以每秒大于60帧的刷新率,才不会让用户感觉到页面卡顿。
在这里插入图片描述

如果在运行动画时,还有大量的js任务需要执行,因为布局绘制和js的执行都是在主线程运行的,当在一帧的时间内,布局和绘制结束后,还有剩余时间,js就会拿到主线程的使用权,如果js执行时间过长就会导致在下一帧开始时,js没有及时归还主线程,导致下一帧动画没有按时渲染,就会出现页面动画的卡顿。
在这里插入图片描述
那有什么优化的手段吗?

有,第一种就是可以通过requestAnimationFrame()这个api来帮助我们解决这个问题。requestAnimationFrame这个方法会在每一帧被调用,通过这个api的回调参数,可以把JS运行任务分成一些更小的任务块(分到每一帧),在每一帧时间用完前暂停JS执行归还主线程,在下一帧开始时主线程就可以按时执行布局和绘制。
在这里插入图片描述

还有第二个优化方法。我们知道栅格化整个流程是不占用主线程的,只在合成器和栅格线程中运行,这就意味着它无需和js抢夺的主线程。刚才提到,如果我们反复重绘和重排,可能会导致掉帧,因为有可能会有js的执行阻塞了主线程。css中有个动画属性叫transform,通过该属性实现的动画,不会经过布局和绘制,而是直接运行在合成器线程和栅格线程中,所以不会受到主线程中js执行的影响。更重要的是transform的动画,由于不需要经过布局绘制样式计算,所以节省了很多运算时间。可以让复杂的动画更加流畅。我们常常通过位置变化、宽高变化来实现动画效果,这些都可以使用transform来代替(transform:translate(x,y)、transform:scale(x,y)、transform:rotate(deg))。

避免重排reflow
reflow 的本质就是重新计算 layout 树。
尽量减少对DOM的操作,特别是那些会引起布局变化的操作。可以通过以下方法来避免:
将多个对DOM的修改合并在一起,使用文档片段(document fragment)或先在非显示状态下进行批量更新,然后一次性应用到DOM上。

let fragment = document.createDocumentFragment(); 
for (let i = 0;i<10;i++){ 
let node = document.createElement("p"); 
node.innerHTML = i; 
fragment.appendChild(node); 
}
document.body.appendChild(fragment); 

使用局部变量缓存DOM元素的几何属性,如宽度、高度等,减少对样式的重复访问。
将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。
不要经常获取同一个元素,可以第一次获取元素后,用变量保存下来,减少遍历时间。
尽量少使用dispaly:none,可以使用visibility:hidden代替,dispaly:none会造成重排,visibility:hidden会造成重绘。
不要使用Table布局,因为一个小小的操作,可能就会造成整个表格的重排或重绘。
使用resize事件时,做防抖和节流处理。
如果要批量添加DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排。

避免重绘repaint
repaint 的本质就是重新根据分层信息计算了绘制指令。
使用CSS的transformopacity属性进行动画,这些变化会创建新的图层,不会触发重绘。
通过requestAnimationFrame来控制动画,可以确保动画在合适的时间高效执行。
将元素提升为合成层,合成层的位图,会交由 GPU 合成,⽐ CPU 处理要快。提升合成层的最好⽅式是使⽤ CSS 的 will-change 属性:

#target { 
will-change: transform; 
}

参考链接:
https://mp.weixin.qq.com/s/_phLApBXsuOun0KeSoIPlQ
https://blog.csdn.net/Poggie/article/details/136487985
https://zhuanlan.zhihu.com/p/503647367

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值