面试官:谈谈你对重绘和回流(重排)的理解?

我们首先来回顾一下渲染流水线的流程:

接下来,我们将来以此为依据来介绍重绘和回流,以及让更新视图的另外一种方式――合成。

1.了解浏览器的渲染机制

  1. 浏览器采用流式布局模型。
  2. 首先浏览器会将HTML解析成DOM,把CSS解析成CSSOM,把CSSOM与DOM结合产生render tree。
  3. 有render tree之后,我们知道了节点样式,然后浏览器会计算节点的位置,然后把节点绘制到页面上。

总结:回流一定会引起重绘,重绘不一定会引起回流。

2.回流(重排)

首先介绍回流。回流也叫重排。

当我们render tree中的一些元素的结构或者尺寸等发生改变,浏览器重新渲染部分或者全部文档的过程就叫做回流。

(1)触发条件
一般来说,就是当我们对DOM结构的修改引发DOM几何尺寸变化的时候,会发生回流的过程。具体一点,有以下的操作会触发回流:

  1. 一个DOM元素的几何属性变化,常见的几何属性有width、height、padding 、margin 、1eft、top、border等等,这个很好理解。
  2. 使DOM节点发生增减或者移动。
  3. 读写offset族、scroll族和client族属性的时候,浏览器为了获取这些值,需要进行回流操作。
  4. 调用window.getcomputedstyle方法。

简单一些,就是有以下操作会导致回流:

  • 页面首页渲染
  • 浏览器窗口大小发生变化
  • 内容变换
  • 添加或者删除节点
  • 激活CSS伪类

(2)回流过程

依照上面的渲染流水线,触发回流的时候,如果DOM结构发生改变,则重新渲染DOM树,然后将后面的流程(包括主线程之外的任务)全部走—遍。

 相当于将解析和合成的过程重新又走了一篇,开销是非常大的。

3.重绘

(1) 触发条件
当DOM的修改导致了样式的变化,并且没有影响几何属性的时候,会导致重绘( repaint)。

一般来说,导致重绘的操作有:

当页面中元素样式的改变不影响它在文档流中的位置,浏览器会将新样式赋予给元素,这个过程叫做重绘,或者是一个元素的外观被改变,(背景色,字体颜色,边框颜色等)

(2)重绘过程
由于没有导致DOM几何属性的变化,因此元素的位置信息不需要更新,从而省去布局的过程。流程如下:

跳过了生成布局树和建图层树的阶段,直接生成绘制列表,然后继续进行分块、生成位图等后面一系列操作。
 

优化思路:

  • 能重绘尽量不重排
  • 能少排不多排
  • 能小区域不大区域排
  • 避免无效重排
  • 利用GPU资源

 合成

还有一种情况,是直接合成。比如利用CSS3的transform、opacity、filter这些属性就可以实现合成的效果,也就是大家常说的GPU加速。


(1)GPU加速的原因
在合成的情况下,会直接跳过布局和绘制流程,直接进入非主线程处理的部分,即直接交给合成线程处理。交给它处理有两大好处:

  • 能够充分发挥GPU的优势。合成线程生成位图的过程中会调用线程池,并在其中使用GPu进行加速生成,而GPU是擅长处理位图数据的。
  • 没有占用主线程的资源,即使主线程卡住了,效果依然能够流畅地展示。

作为一名前端开发人员,需要对浏览器的开销情况也有所了解,重绘和重排都会开销,以下几种方法可以减少开销

(1)分离读写操作

div.style.left ='10px';
div.style.top = '10px ';
div.style.width ='20px';
div.style.height ='20px';
console.log(div.offsetLeft);
console.log(div.offsetTop);
console.log(div.offsetwidth);
console.log(div.offsetHeight);

由于属性读取会强制重排后在读取,所以尽量避免读一个写一个属性读一个属性。
 

(2)  样式集中改变

// bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top = top+ "px" ;
//good
el.className += " theclassname" ;
// good
el.style.cssText += " ; left: " + left + "px; top: " + top + "px; " ;

(3) 缓存布局信息

// bad强制刷新 触发两次重排
div.style.left = div.offsetLeft + 1 + 'px ';
div. style.top = div.offsetTop + 1 + 'px ' ;
// good缓存布局信息 相当于读写分离
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';

(4) 离线改变dom


隐藏要操作的dom

(1) 在要操作dom之前,通过display隐藏dom,当操作完成之后,才将元素的display属性为可见,因为不可见的元素不会触发重排和重绘。

dom.display = 'none'
//修改dom样式
dom .display ='block'

(2) 通过使用DocumentFragment创建一个dom碎片,在它上面批量操作dom,操作完成之后,再添加到文档中,这样只会触发一次重排。

(3) 复制节点,在副本上工作,然后替换它

(5) position属性为absolute或fixed

position属性为absolute或fixed的元素,重排开销比较小,不用考虑它对其他元素的影响
 

(6) 优化动画

  • 可以把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小
  • 动画效果还应牺牲一些平滑,来换取速度
  • GPU硬件加速是指应用GPU的图形性能对浏览器中的一些图形操作交给GPU来完成,因为GPU是专门为处理图形而设计,所以它在速度和能耗上更有效率。GPU加速通常包括以下几个部分:Canvas2D,布局合成,CSS3转换(transitjons) , CSS3 3D变换(transforms) , WebGL和视频(video)。-

实际意义

  • 知道上面的原理之后,对于开发过程有什么指导意义呢?

  • 避免频繁使用style,而是采用修改class的方式。

  • 使用createDocumentFragment进行批量的DOM操作。

  • 对于resize、scroll等进行防抖/节流处理。


添加will-change: tranform,让渲染引擎为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。当然这个变化不限于tranform,任何可以实现合成效果的CSS属性都能用will-change来声明。

这里有一个实际的例子,一行will-change: tranform拯救一个项目。

 

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值