- 优化节点修改。
- 使用
cloneNode
在外部更新节点然后再通过replace
与原始节点互换。
var orig = document.getElementById('container');
var clone = orig.cloneNode(true);
var list = ['foo', 'bar', 'baz'];
var content;
for (var i = 0; i < list.length; i++) {
content = document.createTextNode(list[i]);
clone.appendChild(content);
}
orig.parentNode.replaceChild(clone, orig);
- 优化节点添加
>多个节点插入操作,即使在外面设置节点的元素和风格再插入,由于多个节点还是会引发多次reflow。
- 优化的方法是创建
DocumentFragment
,在其中插入节点后再添加到页面。
- 如JQuery
中所有的添加节点的操作如append
,都是最终调用DocumentFragment
来实现的,
createSafeFragment(document) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment();
if (safeFrag.createElement) {
while (list.length) {
safeFrag.createElement(
list.pop();
);
};
};
return safeFrag;
};
- 优化
CSS
样式转换。
>如果需要动态更改CSS样式,尽量采用触发reflow次数较少的方式。
- 如以下代码逐条更改元素的几何属性,理论上会触发多次reflow
。
element.style.fontWeight = 'bold' ;
element.style.marginLeft= '30px' ;
element.style.marginRight = '30px' ;
- 可以通过直接设置元素的`className`直接设置,只会触发一次`reflow`。
element.className = 'selectedAnchor' ;
- 减少
DOM
元素数量
- 在console
中执行命令查看DOM
元素数量。
`document.getElementsByTagName( '*' ).length`
- 正常页面的`DOM`元素数量一般不应该超过`1000`。
- `DOM`元素过多会使`DOM`元素查询效率,样式表匹配效率降低,是页面性能最主要的瓶颈之一。
DOM
操作优化。
- DOM
操作性能问题主要有以下原因。
- DOM
元素过多导致元素定位缓慢。
- 大量的DOM
接口调用。
- JAVASCRIPT
和DOM
之间的交互需要通过函数API
接口来完成,造成延时,尤其是在循环语句中。
- DOM
操作触发频繁的reflow(layout)
和repaint
。
- layout
发生在repaint
之前,所以layout相对来说会造成更多性能损耗。
- reflow(layout)
就是计算页面元素的几何信息。
- repaint
就是绘制页面元素。
- 对DOM
进行操作会导致浏览器执行回流reflow
。
- 解决方案。
- 纯JAVASCRIPT
执行时间是很短的。
- 最小化DOM
访问次数,尽可能在js端执行。
- 如果需要多次访问某个DOM
节点,请使用局部变量存储对它的引用。
- 谨慎处理HTML
集合(HTML
集合实时连系底层文档),把集合的长度缓存到一个变量中,并在迭代中使用它,如果需要经常操作集合,建议把它拷贝到一个数组中。
- 如果可能的话,使用速度更快的API,比如querySelectorAll
和firstElementChild
。
- 要留意重绘和重排。
- 批量修改样式时,离线
操作DOM
树。
- 使用缓存,并减少访问布局的次数。
- 动画中使用绝对定位,使用拖放代理。
- 使用事件委托来减少事件处理器的数量。
- 优化
DOM
交互
>在JAVASCRIPT
中,DOM
操作和交互要消耗大量时间,因为它们往往需要重新渲染整个页面或者某一个部分。
- 最小化现场更新
。
- 当需要访问的DOM
部分已经已经被渲染为页面中的一部分,那么DOM
操作和交互的过程就是再进行一次现场更新
。
- 现场更新
是需要针对现场
(相关显示页面的部分结构)立即进行更新,每一个更改(不管是插入单个字符还是移除整个片段),都有一个性能损耗。
- 现场更新进行的越多,代码完成执行所花的时间也越长。
- 多使用innerHTML
。
- 有两种在页面上创建DOM
节点的方法:
- 使用诸如createElement()
和appendChild()
之类的DOM
方法。
- 使用innerHTML
。
- 当使用innerHTML
设置为某个值时,后台会创建一个HTML
解释器,然后使用内部的DOM
调用来创建DOM
结构,而非基于JAVASCRIPT
的DOM
调用。由于内部方法是编译好的而非解释执行,故执行的更快。
>对于小的DOM
更改,两者效率差不多,但对于大的DOM
更改,innerHTML
要比标准的DOM
方法创建同样的DOM
结构快得多。
- 回流
reflow
。
- 发生场景。
- 改变窗体大小。
- 更改字体。
- 添加移除stylesheet块。
- 内容改变哪怕是输入框输入文字。
- CSS虚类被触发如 :hover。
- 更改元素的className。
- 当对DOM节点执行新增或者删除操作或内容更改时。
- 动态设置一个style样式时(比如element.style.width="10px")。
- 当获取一个必须经过计算的尺寸值时,比如访问offsetWidth、clientHeight或者其他需要经过计算的CSS值。
- 解决问题的关键,就是限制通过DOM操作所引发回流的次数。
- 在对当前DOM进行操作之前,尽可能多的做一些准备工作,保证N次创建,1次写入。
- 在对DOM操作之前,把要操作的元素,先从当前DOM结构中删除:
- 通过removeChild()或者replaceChild()实现真正意义上的删除。
- 设置该元素的display样式为“none”。
- 每次修改元素的style属性都会触发回流操作。
element.style.backgroundColor = "blue";
- 使用更改`className`的方式替换`style.xxx=xxx`的方式。
- 使用`style.cssText = '';`一次写入样式。
- 避免设置过多的行内样式。
- 添加的结构外元素尽量设置它们的位置为`fixed`或`absolute`。
- 避免使用表格来布局。
- 避免在`CSS`中使用`JavaScript expressions(IE only)`。
- 将获取的`DOM`数据缓存起来。这种方法,对获取那些会触发回流操作的属性(比如`offsetWidth`等)尤为重要。
- 当对HTMLCollection对象进行操作时,应该将访问的次数尽可能的降至最低,最简单的,你可以将length属性缓存在一个本地变量中,这样就能大幅度的提高循环的效率。