DOM 操作性能调优
JavaScript 的开发离不开 DOM 的操作,所以对 DOM 操作的性能调优在 Web 开发中也是非常重要的。
Repaint 和 Reflow
Repaint 也叫 Redraw,它指的是一种不会影响当前 DOM 的结构和布局的一种重绘动作。如下动作会产生 Repaint 动作:
不可见到可见(visibility 样式属性)
颜色或图片变化(background, border-color, color 样式属性)
不改变页面元素大小,形状和位置,但改变其外观的变化
Reflow 比起 Repaint 来讲就是一种更加显著的变化了。它主要发生在 DOM 树被操作的时候,任何改变 DOM 的结构和布局都会产生 Reflow。但一个元素的 Reflow 操作发生时,它的所有父元素和子元素都会放生 Reflow,最后 Reflow 必然会导致 Repaint 的产生。举例说明,如下动作会产生 Repaint 动作:
浏览器窗口的变化
DOM 节点的添加删除操作
一些改变页面元素大小,形状和位置的操作的触发
减少 Reflow
通过 Reflow 和 Repaint 的介绍可知,每次 Reflow 比其 Repaint 会带来更多的资源消耗,我们应该尽量减少 Reflow 的发生,或者将其转化为只会触发 Repaint 操作的代码。
参考如下代码:
清单 16. reflow 介绍
- var pDiv = document.createElement(“div”);
- document.body.appendChild(pDiv);----- reflow
- var cDiv1 = document.createElement(“div”);
- var cDiv2 = document.createElement(“div”);
- pDiv.appendChild(cDiv1);----- reflow
- pDiv.appendChild(cDiv2);----- reflow
这是我们经常接触的代码了,但是这段代码会产生 3 次 reflow。再看如下代码:
清单 17. 减少 reflow
- var pDiv = document.createElement(“div”);
- var cDiv1 = document.createElement(“div”);
- var cDiv2 = document.createElement(“div”);
- pDiv.appendChild(cDiv1);
- pDiv.appendChild(cDiv2);
- document.body.appendChild(pDiv);----- reflow
这里便只有一次 reflow,所以我们推荐这种 DOM 节点操作的方式。
关于上述较少 Reflow 操作的解决方案,还有一种可以参考的模式:
清单 18. 利用 display 减少 reflow
- var pDiv = document.getElementById(“parent”);
- pDiv.style.display = “none”----- reflow
- pDiv.appendChild(cDiv1);
- pDiv.appendChild(cDiv2);
- pDiv.appendChild(cDiv3);
- pDiv.appendChild(cDiv4);
- pDiv.appendChild(cDiv5);
- pDiv.style.width = “100px”;
- pDiv.style.height = “100px”;
- pDiv.style.display = “block”----- reflow
先隐藏 pDiv,再显示,这样,隐藏和显示之间的操作便不会产生任何的 Reflow,提高了效率。
特殊测量属性和方法
DOM 元素里面有一些特殊的测量属性的访问和方法的调用,也会触发 Reflow,比较典型的就是“offsetWidth”属性和“getComputedStyle”方法。
图 1. 特殊测量属性和方法
这些测量属性和方法大致有这些:
offsetLeft
offsetTop
offsetHeight
offsetWidth
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
getComputedStyle()