整理阅读:高性能JS

本文探讨了浏览器中DOM操作的性能优化方法,包括减少DOM访问、使用局部变量存储更新内容及改进HTML集合操作等技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 浏览器中DOM操作的性能优化     

         频繁地对于DOM进行操作的是很损耗性能,但在富网页应用中我们编写脚本无可避免地要访问或修改DOM,怎么优化这个性能瓶颈使我们经常碰到的难题之一,最近被公司一个大项目在性能方面折腾得够伤,所以针对遇到的问题做一些小总结和探讨。浏览器中DOM操作的性能优化大致从以下三种情况去考虑:

1.访问和修改DOM元素
2.为了页面的重绘和重新排版修改DOM样式
3.通过DOM事件处理程序来响应用户

下面仔细谈谈怎么优化浏览器中DOM操作的性能。

访问和修改DOM元素

在浏览器中,DOM的实现和Javascript的实现通常是保持相互独立的。首先了解一下主流浏览器的渲染引擎和JS引擎:

  浏览器  

  渲染引擎(内核)  

  JS引擎  

IE

  mshtml.dll(Trident)  

JScript

Chrome

  WebCore(WebKit)  

V8

FireFox

  Gecko  

 Spider-Monkey/TraceMonkey 

Safari

  WebCore(WebKit)  

 JavaScriptCore/SquirrelFish 

为什么访问DOM对性能有影响?

因为DOM和Javascript作为两个独立的部分,通过他们各自的接口来连接就会带来性能损耗。打个比喻,把DOM看成一个城市A,把Javascript看成另外一个城市B,两者之间以一条要收费的高速公路连接,每次Javascript访问DOM都需要过路,交一次高速公路过路费。来回多了费用自然就高。所以我们得想方设法减少过路的次数。
  访问DOM元素的代价就是交一次“过路费”,修改DOM元素则会导致浏览器重新计算页面的几何变化。如果是循环修改DOM元素,其代价可想而知。如下代码:

function innerHTMLLoop1(){    

for(var count=0;count<10000;count++){    

      document.getElementById("test").innerHTML+="增加内容";    

}

在这段代码中,每循环一次都要对DOM元素访问两次:一次是读取innerHTML属性的内容,另一次是把新的内容写入它。所以一个优化的办法就是使用一个局部变量存储更新后的内容,在循环结束时再一次性写入:

function innerHTMLLoop2(){
 var content ="";    

for(var count=0;count<10000;count++){     

      content+="增加内容";    

}    

document.getElementById("test").innerHTML +=content ; 

}

很明显,innerHTMLLoop2交的“过路费”明显要少很多,因为它只访问了两次DOM元素,一次读入,一次写入。所以一般的法则是:尽量在自己的范围内(Javascript城市)活动。

更新页面的两种方法性能比较:innerHTML和DOM方法(如document.creatElment)。《高性能Javascript编程》的答案是:性能差别不大,innerHTML好一些,使用简单嘛。另外还有一个更新页面的方法是节点克隆--element.cloneNode()。

HTML集合的操作

HTML集合是用于存放DOM节点引用的类数组对象。可通过下列的方法或属性得到这样的集合:

document.getElementsByName()
document.getElementsByTagName()
document.getElementsByClassName()
document.images 返回对文档中所有 Image 对象引用
document.links  返回对文档中所有 Area 和 Link 对象引用
document.forms 返回对文档中所有 Form 对象引用
document.forms[0].elements 返回对文档中第一个表单的所有元素

HTML集合会实时查询文档信息,也就是说当你要用到这个集合时,它会自动查询文档的最新信息。请看如下代码:

var allDivs =document.getElementsByTagName("div"); 

for(var i=0;i<allDivs.length;i++){ 

    document.body.appendChild(document.createElement("div")); 

}

例如像上面的那段代码其实是个死循环,因为每一次访问div集合的length属性,它都会重新计算文档中的div元素数目。这就是html集合低效率的来源。要改进代码就用一个局部变量保存div集合的length属性:for(var i=0, len=allDivs.length; i<len; i++){...}

访问HTML集合的length比数组的length要慢,所以要访问这种集合类的数目length,我们都应该先用一个局部变量去保存它:var len = 集合.length;

另外,访问数组的元素要比访问HTML集合的元素要快。所以我们可以先把HTML集合转换成数组才去进行相应的操作:

//HTML集合转换成数组 

function toArray(coll){   

for(var a=[], i=0, len=coll.legnth; i<len; i++){      

      a[i] =coll[i];    

}    

return a; 

//使用 

var coll =document.getElementsByTagName("div"); 

var divs = toArray(coll);

有人可能会问,这样多用了一个数组副本到底值不值得?这个倒是要看情况吧。不过另外一种选择,使用局部变量:

function loopColletion(){   

var coll =document.getElmentsByTagName("div"),     

len = coll.length,     

el = null;    

for(var i = 0; i<len; i++){      

      el =coll[i];      //然后访问局部变量el   

}

许多浏览器提供了API函数返回元素节点,这些API都是原生的,所以可用的话就尽量用。下图列举了一些DOM的属性:

  

 上图列举的所有属性能被FF,safari,chrome,opera所支持,ie6-8只支持children。

遍历children比childNodes更快,因为集合项少了。HTML源码中的空格实际上是文本节点,但他们不包含在children中。

另外还有两个比较好的选择器API:document.querySelectorAll()和document.querySelector()。前者接收一个CSS选择器字符串参数并返回一个NodeList类数组对象而不是返回HTML集合,后者只返回符合查询条件的第一个节点。很遗憾IE6、7不支持这两个API。

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值