Javascript访问HTML DOM树里的效率问题
这阵子在做一个仿Outlook发邮件时输入收文人的控件,要求在用户输入字符串后能显示出以该字符串开头的用户/组列表(总数接近4000)供选择。用户/组列表在HTML里存储在Table的TBody里,每一个TR代表一个列表项。当用户输入字符串的时候需要去遍历这些列表项,使用了如下的for语句:
- for (i = 0; i < this .tbody.rows.length; i++)
测试后发现这个for循环大概需要2200毫秒左右,这个速度根本不能接受。刚开始还以为是for循环里面代码的问题,测试了一下,发现里面代码的效率不至于如此低。后来更改了一下for语句的写法:
- var l = this .tbody.rows.length;
- for (i = 0; i < l; i++)
for循环的执行时间降低到了70多毫秒,可见问题是出在this
.tbody.rows.length的计算上。当HTML页面的DOM树很大时,其访问效率应该是比较差的,不过我没想到访问一个数组的长度都有如此大的效率问题。
一方面,这个问题的造成是由于我的疏忽引起的,使用循环时,循环条件语句里最好都使用计算好的本地变量(除非循环体内代码会影响到循环条件),这样可以将效率提高到最优。其实循环内的不变量使用本地变量预先缓存可以提高执行效率。这个原则不只对Javascript代码适用,应该大多数甚至全部编程语言都适用。(当然这样做也可能带来代码可阅读性的下降和代码长度的增加,这就要看具体情况决定如何做了,如果循环的次数相当大时,则最好是使用本地变量缓存不变量)
另一方面,这个问题也说明了Javascript访问HTML DOM树的效率是比较慢的,当DOM树比较小时还无所谓,当DOM树大到了一定程度时,其效率就难以接受了。上面的例子中,循环体内有一句访问TBody里每一行数据的代码:
- if ( this .tbody.rows[i].cells[0].innerText.toLowerCase().indexOf(str) == 0)
加上这段代码后,即使是使用上面for循环的第二种写法,也需要500多毫秒的执行时间,而将数据缓存在一个数组中,使用如下代码访问数据时,执行时间则是70多毫秒:
- if ( this .data[i][0].toLowerCase().indexOf(str) == 0)
下一篇: 大数据时代,银行BI应用的方案探讨