一般来说,对于任何类型的DOM访问,如果同一个DOM属性或方法被访问一次以上,最好使用一个局部变量缓存此DOM成员。当遍历一个集合时,第一个优化是将集合引用存储于局部变量,并在循环之外缓存length属性。然后,如果在循环体中多次访问同一个集合元素,那么使用局部变量缓存它。
在下面的例子中,在循环中访问每个元素的三个属性。最慢的版本每次都要访问全局的document,优化后的版本缓存了一个指向集合的引用,最快的版本将集合的当前元素存入局部变量。所有三个版本都缓存了集合的length属性。
// slow
function collectionGlobal() {
var coll = document.getElementsByTagName_r('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = document.getElementsByTagName_r('div')[count].nodeName;
name = document.getElementsByTagName_r('div')[count].nodeType;
name = document.getElementsByTagName_r('div')[count].tagName;
}
return name;
};
// faster
function collectionLocal() {
var coll = document.getElementsByTagName_r('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = coll[count].nodeName;
name = coll[count].nodeType;
name = coll[count].tagName;
}
return name;
};
// fastest
function collectionNodesLocal() {
var coll = document.getElementsByTagName_r('div'),
len = coll.length,
name = '',
el = null;
for (var count = 0; count < len; count++) {
el = coll[count];
name = el.nodeName;
name = el.nodeType;
name = el.tagName;
}
return name;
};
DOM API提供了多种途径访问整个文档结构的特定部分。当你在多种可行方法之间进行选择时,最好针对特定操作选择最有效的API。
你经常需要从一个DOM元素开始,操作周围的元素,或者递归迭代所有的子节点。你可以使用childNode集合或者使用nextSibling获得每个元素的兄弟节点。
考虑这两个同样功能的例子,采用非递归方式遍历一个元素的子节点:
function testNextSibling() {
var el = document.getElementById('mydiv'),
ch = el.firstChild,
name = '';
do {
name = ch.nodeName;
} while (ch = ch.nextSibling);
return name;
};
function testChildNodes() {
var el = document.getElementById('mydiv'),
ch = el.childNodes,
len = ch.length,
name = '';
for (var count = 0; count < len; count++) {
name = ch[count].nodeName;
}
return name;
};
记住,childNodes是一个集合,要小心处理,在循环中缓存length属性所以不会在每次迭代中更新。
在IE6中,nextSibling比对手快16 倍,而在IE7中快乐105倍。鉴于这些结果,在老的IE中性能严苛的使用条件下,用nextSibling抓取DOM 是首选方法。
DOM属性诸如childNode,firstChild,和nextSibling不区分元素节点和其他类型节点,如注释节点和文本节点(这两个标签之间往往只是一些空格)。在许多情况下,只有元素节点需要被访问,所以在循环中,似乎应当对节点返回类型进行检查,过滤出非元素节点。这些检查和过滤都是不必要的DOM 操作。
许多现代浏览器提供了API函数只返回元素节点。如果可用最好利用起来,因为它们比你自己在JavaScript中写的过滤方法要快。
遍历children比childNodes更快,因为集合项更少。HTML源码中的空格实际上是文本节点,它们不包括在children集合中。在所有浏览器中children比childNodes更快,虽然差别不是太大,通常快1.5 到3倍。特别值得注意的是IE,遍历children 明显快于遍历childNodes——在IE6中快24 倍,在IE7中快124倍。