正文
从性能角度来讲,这样做会快很多。同时,因为对HTML集合的访问比对数组访问要更耗费性能,因此在某些不得不多次访问HTML集合的情况下,可以先将集合存储为一个数组,然后对数组进行访问:
function toArray(htmlList){
for (var i = 0, htmlArray = [], len = htmlList.length; i < len; i++){
htmlArray[i] = htmlList[i];
}
return htmlArray;
}
当然,这也需要额外的开销,需要自己进行权衡是否有必要这样做。
Local variables when accessing collection elements 访问集合元素时使用局部变量
对于任何类型的DOM访问,如果对同一个DOM属性或者方法访问多次,最好使用一个局部变量对此DOM成员进行缓存。特别是在HTML集合中访问元素时,如果多次对集合中的某一元素访问,同样需要将这个元素先进行缓存。
Walking the DOM DOM漫谈
DOM API提供了多种访问文档结构特定部分的方法,去选择最有效的API。
Crawling the DOM 抓取DOM
如果你可以通过:document.getElementByID();获得某元素就不要去用document.getElementById().parentNode;这么麻烦去获取。如果你可已通过nextSibling去获取一个元素就不要通过childNodes去获取,因为后者是一个nodeList集合。
Element nodes 元素节点
DOM包含三个节点(也可以说是四个):元素节点、属性节点、文本节点(以及注释节点);通常情况下,我们获取到和使用的是元素节点,但是我们通过childNodes、firstChild、nextSibling等方法获取到的是所有节点的属性,js中有一些其他的API可以用来只返回元素节点或者元素节点的某些属性,我们可以用这些API取代那些返回整个全部节点或者节点属性的API,例如:
childNodes
children
childNodes.length
childElementCount
firstChild
firstElementChild
lastChild
lastElementChild
nextSibling
nextElementSibling
previousSibling
previousElementSibling
在所有的浏览器中,后者比前者要快,只不过IE中后面部分方法并不支持,比如IE6/7/8,只支持children方法。
The Selectors API 选择器API
传统的选择器在性能方面问题不大,只不过应用场景相对单一,当我们用习惯了CSS选择器之后,我们会觉得DOM给我们提供的选择器让我们抓狂。在querySelector/querySelectorAll之前,如果我们想要查找到元素下符合条件的另一元素时,不得不使用类似下面的方法:document.getElementById("id1").getElementById("id2");,但如果你想获取一个类名为class1或类名为class2的div的时候,不得不这么处理:
function getDivClass1(className1,className2){
var results = [];
divs = document.getElementByTagName("div");
for (var i = 0,len = divs.length; i < len; i++){
_className = divs[i].className;
if(_className === className1 || _className === className2){
results.push(divs[i]);
}
}
return results;
}
不仅仅是因为冗长的代码,多次对DOM进行遍历带来的性能问题也不可小窥;不过在有了querySelector/querySelectorAll之后,这一切变得简单,减少对DOM的遍历也带来了性能的提升。上面两个例子可以重写如下:
document.querySelector("#id1 #id2");
document.querySelectorAll("div.className1,div.className2");
因此,如果可以,尽量使用querySelector/querySelectorAll吧。
Repaints and Reflows 重绘和重排(也称回流)
这涉及到一个比较古老的议题,浏览器在拿到服务器响应时都干了什么。我查阅了相当一部分资料(网上很多地方说法是不准确的,包括一些问答、博客),去了解整个流程,这里简单的描述一下过程。更多细节可参考《浏览器的工作原理:新式网络浏览器幕后揭秘》,原版地址(http://taligarsiel.com/Projec...)。
上文提到过,浏览器的实现一般包括渲染引擎和JavaScript引擎;二者是相互独立的。
我们先从渲染引擎的角度来看一下在拿到服务器的文档后的处理流程:
Parsing HTML to construct the DOM tree 解析HTML以构建DOM tree
解析HTML文档,将各个标记逐个转化为DOM tree 上的DOM节点;当然并不是一一对应;类似于head这样的标记是在DOM tree上是没有对应的节点的。在这个过程中,同时被解析的还包括外部CSS文件以及样式元素中的样式数据,这些数据信息被准备好进行下一步工作。
Render tree construction 构建render tree
在DOM tree构建过程中,CSS文件同时被解析,DOM tree上每一个节点的对应的颜色尺寸等信息被保存在另一个被称作rules tree的对象中(具体实现方式webkit和gecho是不一样的,可参考上文提到过的《浏览器的工作原理》)。DOM tree和rules tree两者一一对应,均构建完成之后,render tree也就构建完成了。