性能提升:重绘与重排的二三事

151 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天。

概念区分

浏览器下载完页面中的所有组件——HTML、JavaScript、CSS、图片等之后,会解析为两个内部的数据结构:

  • DOM 树:表示页面结构

  • 渲染树:表示 DOM 节点如何显示

DOM 树中显示的每一个节点在渲染树中都存在至少一个对应的节点,渲染树是符合 CSS 模型定义的,比如盒模型等。一旦 DOM 和渲染树构建完成,浏览器就开始绘制页面元素。

重排

几何属性的变化(比如改变宽高、边框等),会使渲染树中受影响的部分失效,导致重新构造渲染树,这个过程我们称为重排。

重绘

完成重排后,浏览器会重新绘制受影响的部分到屏幕中,这个过程我们叫做重绘。

重排发生的时机

  • 改变 DOM 元素(添加或删除)

  • 元素位置改变

  • 元素尺寸改变(外边框,内边框,宽高,边框等)

  • 浏览器窗口尺寸改变

  • 滚动条(整个页面重排)

不会引起几何属性变化的情况

  • 改变背景色(只重绘不重排)

  • 改变文字颜色

性能优化的思路

重绘和重排会降低程序的响应速度,优化的方向就是减少此类操作的发生。我们要做的就是合并多次对 DOM 和样式的修改,然后一次处理掉。

通过延迟访问布局信息来避免重排所带来的性能提升图示:

图片.png

1合并样式的优化

优化前:

var el = document.getElementById('mydiv)
el.style.borderLeft = '1px'
el.style.borderRight = '2px'
el.style.padding = '5px'

可以使用cssText进行优化:

var el = document.getElementById('mydiv)
el.style.cssText = 'border-left: 1px; border-right:2px; padding: 5px'

2批量修改 DOM

可以通过以下步骤减少重绘和重排次数:

  1. 使元素脱离文档流
    • 隐藏元素
    • 使用文档片段:createDocumentFragment(推荐方法,DOM 遍历与重排次数最少)
    • 将原始元素拷贝到一个脱离文档的结点中,修改副本,完成后再替换原始元素
  2. 对其应用多重改变
  3. 把元素带回文档中

性能提升小结

  • 要留意重绘和重排:批量修改样式时,“离线”操作DOM树,使用缓存,减少访问布局信息的次数。

  • 使用事件委托来减少事件处理器的数量。

  • 最小化DOM访问次数,尽可能在JavaScript端处理。

  • 如果需要多次访问某个DOM 节点,使用局部变量存储它的引用。

  • 动画中使用绝对定位,使用拖放代理。

  • 小心处理HTML集合,因为它实时连系着底层文档。把集合的长度缓存到一个变量中,并在迭代中使用它。如果需要经常操作集合,建议把它拷贝到一个数组中。

  • 如果可能的话,使用速度更快的API,比如querySelectorAll()和firstElementChild