如何提升JavaScript的运行速度(DOM篇)(2)
作者:Nicholas C. Zakas 来源:nczonline.net 发布时间:2010-05-17 13:32:00
避免不必要回流操作的另外一种方法,就是在对DOM操作之前,把要操作的元素,先从当前DOM结构中删除。对于删除一个元素,基本有两种方法:
1. 通过removeChild()或者replaceChild()实现真正意义上的删除。
2. 设置该元素的display样式为“none”。
而一旦修改操作完成,上面这个过程就需要反转过来,将删除的元素重新添加到当前的DOM结构中,我们还是拿上面的例子来做说明:
/*list.style.display = "none";for (var i=0; i < items.length; i++){ var item = document.createElement("li"); item.appendChild(document.createTextNode("Option " + i); list.appendChild(item);}list.style.display = "";*/
将list的display样式设置为“none”后,就将这个元素从当前的DOM结构中删除了,因为这个节点不再可视。在将display属性设置回之前的默认值之前,向其下添加子元素是不会触发回流操作的。
另外一个经常引起回流操作的情况是通过style属性对元素的外观进行修改。比如下面这个例子:
/*element.style.backgroundColor = "blue";element.style.color = "red";element.style.fontSize = "12em";*/
这段代码修改了三个样式,同时也就触发了三次回流操作。每次修改元素的style属性,都肯定会触发回流操作。如果你要同时修改一个元素的很多样式,最好的办法是将这些样式放到一个class下,然后直接修改元素的class,这可比单独修改元素的样式要强得多。比如下面这个例子:
/*.newStyle { background-color: blue; color: red; font-size: 12em;}*/
这样我们在JavaScript代码中,只需下面这行代码就可以修改样式:
/*element.className = "newStyle";*/
修改元素的class属性,会一次将所有的样式应用在目标元素上,而且只会触发一次回流操作。这样做不止更加有效,而且还更容易维护。
既然DOM几乎在所有情况下都很慢,就很有必要将获取的DOM数据缓存起来。这种方法,不仅对获取那些会触发回流操作的属性(比如offsetWidth等)尤为重要,就算对于一般情况,也同样适用。下面介绍一个效率低的夸张的例子:
/*document.getElementById("myDiv").style.left = document.getElementById("myDiv").offsetLeft + document.getElementById("myDiv").offsetWidth + "px";*/
这里对getElementById()调用了三次,是一个很大的问题,访问DOM是很昂贵的,而这三个调用恰恰访问的是同一个元素,也许我们像下面这样写,会更好一些:
/*var myDiv = document.getElementById("myDiv");myDiv.style.left = myDiv.offsetLeft + myDiv.offsetWidth + "px";*/
我们去掉了一些冗余操作,现在对DOM操作的次数已经被减小了。对于那些使用次数超过一次的DOM值,我们都应该缓冲起来,这样可以避免无谓的性能消耗。
也许,拖慢属性访问速度的罪魁祸首就是HTMLCollection对象。这些对象是object类型的,只要DOM需要返回一组节点时就会使用这个对象,也就是说childNodes属性和getElementsByTagName()的返回值都属于这种情况。我们可能经常会将 HTMLCollection当作数组来使用,但实际上他是一个根据DOM结构自动变化的实体对象。每次你访问一个HTMLCollection对象的属性,他都会对DOM内所有的节点进行一次完整匹配,这意味着下面的代码将导致一个死循环:
/*var divs = document.getElementsByTagName("div");for (var i=0; i < divs.length; i++){ //infinite loop document.body.appendChild(document.createElement("div"));}*/
这段代码为什么会变成死循环呢?因为在每次循环中,将会向document中新增一个div元素,同时也会更新divs这个集合,也就是说循环的索引永远都不会超过divs.length的值,因为divs.length的值是伴随着循环而递增的。每次访问divs.length,就会更新一次集合对象,这可比访问一个普通数组的length属性要付出更大的代价。当对HTMLCollection对象进行操作时,应该将访问的次数尽可能的降至最低,最简单的,你可以将length属性缓存在一个本地变量中,这样就能大幅度的提高循环的效率。
/*var divs = document.getElementsByTagName("div");for (var i=0, len=divs.length; i < len; i++){ //not an infinite loop document.body.appendChild(document.createElement("div"));}*/
修改后的代码已经不是死循环了,因为在每次循环时,len的值都是保持固定不变的。将属性值缓存起来除了更加有效率,还可以保证document不会执行多于一次的查询。
本文是“Speed up your JavaScript”这个系列的最后一篇文章,我希望你现在已经知道如何避免那个脚本失控的对话框,以及如何让你的脚本运行的更快。我所提到的技巧很多别人已经提过了,我只是将它们组织到一起,这样大家可以更容易的找到这些信息。如果你有什么更好的话题需要来我整理,在评论中直接告诉我,或者直接联系我吧。 (翻译:明达)
猜你喜欢
- 数据库系统的安全性包括很多方面。由于很多情况下,数据库服务器容许客户机从网络上连接,因此客户机连接的安全对MySQL数据库安全有很重要的影响
- MySQL中模式就是数据库SHOW DATABASES;show databases;罗列所有数据库名称CREATE DATABASE &l
- 今天在做sql Server 2005的实验的时候碰到的问题,问题描述很清楚,怀疑是我以前给计算机修改了名称而导致的.可以用select @
- 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达式就好办了匹配双字节字符(包括汉字在内
- 内容: ************* 1安装MYSQL后更改了ROOT的密码后用 net startmysql 启动时我就遇到了这样的问题.使
- 很多朋友想用SQL2000数据库的编程方法,但是却又苦于自己是学ACCESS的,对SQL只是一点点的了解而已,这里我给大家提供以下参考---
- 首先说登陆在config.inc.php文件中,有一个选项需要设置查找:$cfg['Servers'][$i]['a
- 个人觉得还是不要使用中文作为文件名的好,虽然我们用的语言是中文,毕竟中文容易出现问题,兼容性不好。用Dreamweaver制作网页时,如果插
- Xml_javascript分页实例:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.
- 设计,用户说好,才是真的好!14期的友商联线,同事认为风格不美观,需要重新设计。这次,我们引入了用户调研,调研数据可以帮助我们快速决策!ED
- 左右布局,图片的宽度不固定。正好前几天测试闭合浮动元素时发现了overflow的特殊现象,倒是正好可以用在这里。测试通过:ie6/7&nbs
- 作为收费应用方面的数据库管理员(DBA),公司首席信息官(CIO)经常邀请我与Sarbanes-Oxley审查员开会讨 * 司数据的安全与整合
- 基础知识-----黄金分割法960px宽度的网格设计的好处无需我多说了,下面主要是复习一下如何作图求出960px宽度下的黄金分割点1、首先沿
- 2009年2月24日,Safari 4.0 beta版正式发布,Safari从它的3.2版本开始就已经支持所有的CSS选择器(包括最新的CS
- 在IE下测试,发现最大值是:18014398509481984(0x40000000000000)另外发现一个奇怪的问题:JS世界居然不存在
- 揭秘一个普通的输入框背后惊人的秘密。某月某日,某项目某页面,需要一个价格区间筛选功能,需求合理,所以设计做上去。这是一个无比普通的输入框。在
- 先看下面例子的效果:<INPUT TYPE="text" NAME=""&
- 以下测试用于去除任何字符串中连线的分隔符 代码如下:--去除字符串中连续的分隔符 declare @str nvarchar(200) de
- 一个ASPJPEG组件综合操作的asp类CLASS相关文章:ASP怎么谈到应用到类的?ASP中类的详细介绍(class Property G
- 交互设计师的一项重要工作就是进行产品原型设计(Prototype Design)。而产品原型设计最基础的工作,就是画出站点的大体wirefr