日期:2014-05-16  浏览次数:20355 次

JavaScript性能初步
JavaScript作为前端的看家本领,写出来的代码应该更加专业,更加高效。今天我来开个头,讲下JS性能方面的一些需要注意的地方。
JavaScript是一种解释型语言,所以无法达到和C/Java之类的水平,限制了它能在客户端所做的事情。但我们还是能做一些事情来提高它的性能的。JS的性能可以分为语言本身部分和非语言部分(比如DOM,XMLHttpRequest,Timer等)。
一、JS语言本身部分
1.多个变量一起声明,减少语句数量。
从理论上来说,一条句语句占用了一个CPU指令周期,所以语句数量少,必然会减少代码执行的时间。只是现在的计算机的运算能力都太快了,以至于感觉不出来这两种写法有什么区别,可以说几乎是没任何影响的。抛去时间这一点,从代码书写的专业程度来说,这一点是占了上风的。
2. Array -> [], Object -> {}, RegExp -> //
在声明数组,对象以及正则的时候,都建议采用以上写法,即使用直接量。它是由js引擎直接解释执行的,而不像new Array(),new Object(), new RegExp()会调用内部构造器。
3.避免使用eval和函数构造器
Eval is evil! 使用eval和函数构造器是很耗性能的,因为它每次都会调用js引擎把源代码转化成可执行代码。另外,eval里面的字符串环境是在运行期间才被解释的。
4.避免使用with
尽管看上去使用with挺方便的,但它会创建一个额外的代码scope,并且这个scope在编译期间是不知道的。
5.避免try{}catch(){}
不要养成动不动就使用try catch代码的习惯,有些时候是没必要的,就让错误抛出来吧。不过有些时候是需要的,比如后台传一个json字符串给前台转换,因为这个时候不知道后台传过来的字符串是否符合json格式的,这个时候又没很好的办法来检查,而且这个时候还得用eval语句,如果不符合格式,程序就出错了,导致别的代码无法执行下去,这个时候是不得不用了。这种情况,建议使用YUI的JSON包。
6.使用局部变量,避免全局变量
这一点在写代码的时候是需要非常谨慎的,因为一旦覆盖了别人声明的变量,后果肯定不堪设想的,特别是多人合作编写的代码,查起来也不容易。我建议都采用闭包形式,让我们的变量尽可能都成为局部变量。
7.如果一个变量或者方法在函数中使用多于1次,则用局部变量先进行保存,以减少变量look up的次数。
这个主要是缩短变量的范围链,不用每次使用都要向上查询。试想如果是全局变量,则每次都要向上查询到window对象为止,我们有理由相信这样是不明智的。这一点有些人说很极端,我却不是这么认为的。
8.巧妙地运用this
JS语言本身就博大精深,this的用法就能很好的体现。有一点需要记住的,this关键字总是指向当前函数的所有者对象(执行空间)s,如果没有明确的指出,就是window对象了。网上说这个的文章很多,建议有兴趣的同学好好研究一下。
9.使用JS原生的方法
我们有理由相信原生的方法肯定比外面再包一层的方法来得快。
10.采用好的算法,以减少时间复杂度。
这一点其实没啥好讲的,这又牵涉到计算机科学中很强大的一个方向:数据结构和算法。这个不是几句话,也不是我能讲得明白的。
11.运用正则,以减少代码复杂度。
这一点也没什么可讲的,正则运用得好的人,写出来的代码会很精简,但可读性会降低一点。正则也不是一天二天就能掌握的,需要日积月累。
12.需要的点还有很多很多,JS性能是一门很有学问的研究课题,需要大家乃至全世界的程序员们不断的挖掘和用实例去证明。这里我们得需要感谢那些努力研究JS语言的一线人员,正是他们的研究成果,才让我们能更好地认识这本强大的语言。

二、非语言部分,以Dom操作为例
1.减少dom操作。
随着ajax的流行,动态操作dom结点也是必然的。一个是用户体验的提升,一个是性能方面的下降,这是需要权衡的。单从性能来说,需要避免大容量的 dom操作。Dom一旦被更改,势必会引起repaint,repaint必然就导致了整棵dom树的reflow,从而影响了性能。但随着dom渲染引擎不断地强大,这个影响几乎可以忽略了。
2.优化dom结点的定位速度。
要想操作dom结点,首先是要定位到这个结点。定位结点有很多很多的方法。有一点需要注意的是,要尽量缩小查询的dom树范围,范围越小,查询速度必然更快。
3.缓存dom对象,争取做到只查询一次。
这一点要做到,是非常不容易的。只查询一次,势必要加大参数传递的频繁程度,这个直接会导致代码的复杂程度,这一点也是需要权衡一下的。
4.使用dom本身的一些已经优化过的方法,如innerHTML, cloneNode, DocumentFragment。
这些方法都是被很好的优化过的,但各种浏览器下面表现得不是很一致,需要实践后才知道,不要被网上一些人盲目的话给骗了,因为网上的文章基本是拷贝来拷贝去,有些文章是很早就写出来的,我们不用去怀疑它的正确性,但我们必须清楚它的适用范围,因为它很可能只是在讲IE浏览器。
5.避免在同一个对象上面重复添加事件
我觉得bug可以分为二种,一种是业务逻辑上的bug,这个就是我们日常所说的bug,还有一种是代码逻辑上的bug,在同一对象上面重复添加相同的事件,就是代码逻辑bug,虽然大多数的时候这可能看不出来有什么影响,但身为程序员,是需要注意的。
6.及时地移除已经用不到的事件
这一点很多人也不大会注意,如果这个事件已经用不到了,还是及时地移除吧,以引起不必要的麻烦。
7.event delegate
事件代理。这个的原理就是事件的冒泡原理,所以在不冒泡的事件中(如focus事件)就失效了。使用事件代理,能极大地减少dom树侦听的事件数量。我们有理由相信事件数量越少,dom对事件的响应速度会更快。
8.关于dom操作需要注意的地方真是太多太多了,不是一篇文章能说得完讲得清。很有可能,以上所说的点在新推出的浏览器上面已经不适用了,所以我们只有实践才能知道真相,平时多看网上别人的研究成果,以便不时之需。
总结:以上说得都很简洁,也没提供任何实例。提到的点也只是整个JS性能里面很小的一个子集,还有太多太多的东西等着我们去挖掘,我这里也只是抛砖引玉罢了。

记得Nicolas Zakas曾经说过前端工程师是所有程序员里面最复杂的工种之一,至今都很感谢这位前端大师级的人物来为我们前端工程师撑腰。每当工作感觉累的时候,我都会想起这句话,并且很欣慰。我们做出来的东西很可能被全世界的人看到,再累也是值得的。
1 楼 babydeed 2010-07-11  
好!支持一下!
2 楼 danielwcai 2010-07-11  
写得不错!如果是原创的话。
3 楼 handy.wang 2010-07-17  
nice.