- 访问和修改DOM元素
- 修改DOM元素的样式会导致重绘(repaint)和重排(reflow)
- 通过处理DOM事件处理与用户的交互
DOM的访问与修改
访问DOM元素是有代价的。修改元素则更为昂贵,因为它会导致浏览器重新计算页面的几何变化。
为了让你对DOM编程带来的性能问题有个量化的了解,请看下面的实例:
function innerHTMLLoop() {
for (var count = 0; count < 15000; count++) {
document.getElementById('here').innerHTML += 'a';
}
}
这个函数循环修改页面元素的内容。这段代码的问题在于,每次循环迭代,该元素都被访问两次:一次读取innerHTML属性值,另一次重写它。
一个效率更高的版本是使用局部变量存储更新后的内容,然后再循环结束后一次性写入:
function innerHTMLLoop2() {
var content = '';
for (var count = 0; count < 15000; count++) {
content += 'a';
}
document.getElementById('here').innerHTML += content;
}
因此,一般经验法则:减少访问DOM的次数,把运算尽量留在ECMAScript这一端处理。
节点克隆
使用DOM方法更新页面内容的另一个途径是克隆已有元素,而不是创建新元素——换句话说,就是使用element.cloneNode()(element表示已有节点)替代document。createElement()。
节点克隆提高效率不是特别明显。
HTML集合
HTML集合是包含了DOM节点引用的类数组对象。以下方法的返回值就是一个集合:
• document.getElementsByName()
• document.getElementsByClassName()
• document.getElementsByTagName()
事实上,HTML集合一直与文档保持着连接,每次你需要最新的信息时,都会重复执行查询的过程,哪怕只是获取集合里的元素的个数(即访问集合的length属性)也是如此。
设置一个集合,并把它拷贝到一个数组中:
var coll = document.getElementsByTagName('div');
var ar = toArray(coll);比较下面两个函数:
//较慢
function loopCollection() {
for (var count = 0; count < coll.length; count++) {/*代码处理*/
}
}
// 较快
function loopCopiedArray() {
for (var count = 0; count < arr.length; count++) {/*代码处理*/
}
}
在每次迭代过程中,读取元素集合的length属性会引发集合进行更新,这在所有浏览器中都有明显的性能问题。优化方法很简单,把集合的长度缓存到一个局部变量中,然后再循环的条件退出语句中使用该变量:
function loopCacheLengthCollection() {
var coll = document.getElementsByTagName('div'),
len = coll.length;
for (var count = 0; count < len; count++) {/*代码处理*/
}
}此函数运行速度和loopCopiedArray()一样快。
访问集合元素时使用局部变量
一般来说,对于任何类型的DOM访问,当同一个DOM属性或方法需要多次访问时,最好使用一个局部变量缓存此成员。当遍历一个集合时,首要优化原则是把集合存储在局部变量中,并把length缓存在循环外部,然后,使用局部变量访问这些需要多次访问的元素。
例子:
// 较慢
function collectionGlobal() {
var coll = document.getElementsByTagName('div'),
len = coll.length,
name = '';
for (var count = 0; count < len; count++) {
name = document.getElementsByTagName('div')[count].nodeName;
name = document.getElementsByTagName('div')[count].nodeType;
name = document.getElementsByTagName('div')[count].tagName;
}
return name;
};
// 较快
function collectionLocal() {
var coll = document.getElementsByTagName('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;
};// 最快
function collectionNodesLocal() {
var coll = document.getElementsByTagName('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;
};
选择器API
考虑如下代码:
var elements = document.querySelectorAll('#menu a');
elements的值包含一个引用列表,指向位于id=“menu”的元素之间的所有a元素。querySelectorALL()方法使用CSS选择器作为参数并返回一个NodeList——包含着匹配节点的类数组对象。这个方法不会返回HTML集合,因此返回的节点不会对应实时的文档结构。
如果不使用querySelectorAll(),为了达到相同目的,代码要冗长一些:
var elements = document.getElementById('menu').getElementsByTagName('a');
这种情况下,elements会是一个HTML集合,所以还需要把它拷贝到一个数组中,才能达到与querySelectorAll()返回值类似的静态列表。
JavaScript优化(二)
最新推荐文章于 2024-04-28 11:43:36 发布