🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 更新视图三种方式 - 回流 - 重绘 - 合成 ### []()回流 另外一个叫法是重排,回流触发的条件就是:**对 DOM 结构的修改引发 DOM 几何尺寸变化的时候**,会发生回流过程。 具体一点,有以下的操作会触发回流: 1. 一个 DOM 元素的几何属性变化,常见的几何属性有`width`、`height`、`padding`、`margin`、`left`、`top`、`border` 等等, 这个很好理解。 1. 使 DOM 节点发生`增减`或者`移动`。 1. 读写 `offset`族、`scroll`族和`client`族属性的时候,浏览器为了获取这些值,需要进行回流操作。 1. 调用 `window.getComputedStyle` 方法。 一些常用且会导致回流的属性和方法: - `clientWidth`、`clientHeight`、`clientTop`、`clientLeft` - `offsetWidth`、`offsetHeight`、`offsetTop`、`offsetLeft` - `scrollWidth`、`scrollHeight`、`scrollTop`、`scrollLeft` - `scrollIntoView()`、`scrollIntoViewIfNeeded()` - `getComputedStyle()` - `getBoundingClientRect()` - `scrollTo()` 依照上面的渲染流水线,触发回流的时候,如果 DOM 结构发生改变,则重新渲染 DOM 树,然后将后面的流程(包括主线程之外的任务)全部走一遍。 ![]() ### []()重绘 当页面中元素样式的改变并不影响它在文档流中的位置时(例如:`color`、`background-color`、`visibility`等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。 根据概念,我们知道由于没有导致 DOM 几何属性的变化,因此元素的位置信息不需要更新,从而省去布局的过程,流程如下: ![]() 跳过了`布局树`和`建图层树`,直接去绘制列表,然后在去分块,生成位图等一系列操作。 可以看到,重绘不一定导致回流,但回流一定发生了重绘。 ### []()合成 还有一种情况:就是**更改了一个既不要布局也不要绘制**的属性,那么渲染引擎会跳过布局和绘制,直接执行后续的**合成**操作,这个过程就叫**合成**。 举个例子:比如使用CSS的transform来实现动画效果,**避免了回流跟重绘**,直接在非主线程中执行合成动画操作。显然这样子的效率更高,毕竟这个是在非主线程上合成的,没有占用主线程资源,另外也避开了布局和绘制两个子阶段,所以**相对于重绘和重排,合成能大大提升绘制效率。** 利用这一点好处: - 合成层的位图,会交由 GPU 合成,比 CPU 处理要快 - 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层 - 对于 transform 和 opacity 效果,不会触发 layout 和 paint 提升合成层的最好方式是使用 CSS 的 will-change 属性 ### []()GPU加速原因 比如利用 CSS3 的`transform`、`opacity`、`filter`这些属性就可以实现合成的效果,也就是大家常说的**GPU加速**。 - 在合成的情况下,直接跳过布局和绘制流程,进入`非主线程`处理部分,即直接交给`合成线程`处理。 - 充分发挥`GPU`优势,合成线程生成位图的过程中会调用线程池,并在其中使用`GPU`进行加速生成,而GPU 是擅长处理位图数据的。 - 没有占用主线程的资源,即使主线程卡住了,效果依然流畅展示。 ## []()总结 - 使用`createDocumentFragment`进行批量的 DOM 操作 - 对于 resize、scroll 等进行防抖/节流处理。 - 动画使用transform或者opacity实现 - 将元素的will-change 设置为 opacity、transform、top、left、bottom、right 。这样子渲染引擎会为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。 - 对于不支持will-change 属性的浏览器,使用一个3D transform属性来强制提升为合成 `transform: translateZ(0);` - rAF优化等等。