持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天。
概念区分
浏览器下载完页面中的所有组件——HTML、JavaScript、CSS、图片等之后,会解析为两个内部的数据结构:
-
DOM 树:表示页面结构
-
渲染树:表示 DOM 节点如何显示
DOM 树中显示的每一个节点在渲染树中都存在至少一个对应的节点,渲染树是符合 CSS 模型定义的,比如盒模型等。一旦 DOM 和渲染树构建完成,浏览器就开始绘制页面元素。
重排
几何属性的变化(比如改变宽高、边框等),会使渲染树中受影响的部分失效,导致重新构造渲染树,这个过程我们称为重排。
重绘
完成重排后,浏览器会重新绘制受影响的部分到屏幕中,这个过程我们叫做重绘。
重排发生的时机
-
改变 DOM 元素(添加或删除)
-
元素位置改变
-
元素尺寸改变(外边框,内边框,宽高,边框等)
-
浏览器窗口尺寸改变
-
滚动条(整个页面重排)
不会引起几何属性变化的情况
-
改变背景色(只重绘不重排)
-
改变文字颜色
性能优化的思路
重绘和重排会降低程序的响应速度,优化的方向就是减少此类操作的发生。我们要做的就是合并多次对 DOM 和样式的修改,然后一次处理掉。
通过延迟访问布局信息来避免重排所带来的性能提升图示:
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
可以通过以下步骤减少重绘和重排次数:
- 使元素脱离文档流
- 隐藏元素
- 使用文档片段:createDocumentFragment(推荐方法,DOM 遍历与重排次数最少)
- 将原始元素拷贝到一个脱离文档的结点中,修改副本,完成后再替换原始元素
- 对其应用多重改变
- 把元素带回文档中
性能提升小结
-
要留意重绘和重排:批量修改样式时,“离线”操作DOM树,使用缓存,减少访问布局信息的次数。
-
使用事件委托来减少事件处理器的数量。
-
最小化DOM访问次数,尽可能在JavaScript端处理。
-
如果需要多次访问某个DOM 节点,使用局部变量存储它的引用。
-
动画中使用绝对定位,使用拖放代理。
-
小心处理HTML集合,因为它实时连系着底层文档。把集合的长度缓存到一个变量中,并在迭代中使用它。如果需要经常操作集合,建议把它拷贝到一个数组中。
-
如果可能的话,使用速度更快的API,比如querySelectorAll()和firstElementChild