您现在的位置:首页 > 技术 > JavaScript知识笔记5:优化JavaScript性能

JavaScript知识笔记5:优化JavaScript性能

周知JS语法相对简单,语言结构简单,这样的特性致使我们在书写JS代码的时候一方面很容易,一方面很纠结。容易的是得到结果的方法很多我们可以根据自己的需求组合获得,纠结的是怎么才能让自己的JS代码逻辑最简化、性能最优。实践告诉我们代码量并不是决定执行速度的真正原因,代码量少不一定运行速度快,代码量多不一定运行速度慢。

2016年07月

透明伽然

代码整体结构是执行速度的决定因素之一。下面我们就几种常见的基础算法来阐述性能优化问题。

1.  基本循环介绍

在大多数变成语言中,循环式最常见的模式之一,尤其是JS中,在我刚接触JS的阶段,经常会不知不觉地陷入死循环或者循环长时间的运行。

1)  JS中最基础的有四种循环:or循环、while循环、do..while循环、for..in循环。

2)  forfor..in 在之前已经回顾过,不再重复。补充一点,for..in循环式相比其他几种循环明显要慢。因为它在执行每次迭代操作都会搜索实例或原型的属性,随着每次迭代都会增加开销。

3)  while循环是一种预判断循环,在循环执行前先进行条件判断,结果为true则执行循环体,否则跳出。while循环判断条件是可变的,倘若判断条件是:undefinednullfalse-0+0NaN、‘’之外的直接变量,则与while(true){} 等同,无限循环。


4)  do..while循环式JS中唯一一种后判断的循环,语义理解先做后判断。因此循环至少执行一次,之后再进入while条件判断决定循环体是否再次执行。

forwhile循环其实并不是遍历每一个数组元素,而是在每次迭代直接获取数组对应索引的值,针对性较for..in逐一遍历对象要强,所以时耗必然少。

2.  减少循环迭代的工作量

以上的forwhiledo..while循环相比for..in的速度都在不同程度有所提升,但是我们观察这三种循环每次迭代都会重复以下几项工作:

1)读取arr.length

2)进行一次i<arr.length比较

3)判断i<arr.length结果是否为true

4)进行一次自增 i++

5)查找一次数组元素 arr[i]

6)调用一次控制台输出函数 console.log(arr[i])

寻思以上的例子, arr.length是定值不会改变,但是每次迭代都会执行取数组的长度的操作,这是不必要的浪费。试图用变量保存数组的长度,在控制条件中使用这个变量。JS在读取一个变量值的速度远远要比获取数组长度的时间要提升很多,所以整个循环体执行速度更快了。


关于数组遍历,我们也可以用倒序循环,或者说是大多数语言中都有的性能优化方法。代码如下:

这里用到了JS会将变量隐式转换为布尔类型的特性,但是0的转换结果是false。将上述操作中23步操作合并为一步,直接判断转换结果是不是为true,因此提升性能是必然的。

3.  减少循环的次数

即使循环体中最快的代码,累计迭代上千次(也将是不小的负担)。此外,每次运行循环体时都会产生一个很小的性能开销,也会增加总的运行时间。减少循环的迭代次数可获得显著的性能提升。

减少循次数同时要求完成相对应的工作,这里我们提到一个“达夫设备”这样一个名词,相对很多没有C语言基础的程序员或许并不知道它的存在。

达夫设备是一个加速循环语句的C编码技巧。其基本思想是--减少循环测试的执行次数。

JS也可以应用“达夫设备”这个展开循环的方法,下面附上这样一段代码:

代码的结构显得非常巧妙,但是有些毫无头绪。但是,执行这段代码结果是我们想要的结果。

开始分析这段代码:把一个switch语句和一个do-while语句糅合在了一起。每次循环中最多可 8 次调用console.log()函数。循环迭代次数为元素总数除以8。 因为总数不一定是 8的整数倍, 所以 startAt 变量存放余数, 指出第一次循环中应当执行多少次console.log()。比方说现在有 17 个元素,那么第一次循环将调用console.log()1次,第二次循环调用console.log()8 次,用 2 次循环代替了 17次循环。

针对以上的解释,再看看下面的代码,会有更大地收获。

4.  条件表达式正确使用

JS代码中if..elseswitch条件表达式是最为常见的,最容易被书写但最不容易被重视的一种逻辑。这里有几种优化使用条件表达式做法可以帮助我们。

1)根据需求合理选择使用if..elseswitch表达式。这主要取决于条件的数量,一般来说使用if..else主要用来判断只有两种情况,通俗地讲就是:如果不是真,那么肯定是假。switch用来作多项值筛选,代码的可读性更好。

2)思考优化if..else。程序解读顺序是先比较if中的条件,如果符合执行if中的代码,否则执行else中的代码。常规思路是if中必然是我们想要去执行的代码,那么我们就考虑怎么去优化if中的条件,让它最大几率地匹配。

3)使用if..else if..else语句实现多分支选择结构,这样的结构是在我们在处理多条件循环时,优化多if..else嵌套方法。前面我们说过多条件筛选判断首选switch表达式,这里需要根据具体条件而定。对于只针对变量筛选的情况,选择switch表达式书写,针对多个值域条件筛选,if..else不失为一种好的选择。

4)一个 switch 表达式更适合于每个键需要一个独特的动作,或者一系列动作的场合。

5)在真正的代码处理过程中,有时候我们会针对一些多值域筛选,为了能让我们更快地进入正确分支,这里推荐使用二分搜索法。将值域分成一系列值域区间,然后逐渐缩小范围。


以上三种条件表达式,实现的结果是一样的。switch方式效率最优。

5.  查表法

对于前面我们列举的几种值域判断书写方式,这里给大家介绍一个更优化的方法——查表法。switch 表达式代码所占的空间可能与它的重要性不成比例。整个结构可以用一个数组查表替代:与 if-else switch 相比,查表法不仅非常快,而且当需要测试的离散值数量非常大时,也有助于保持代码的可读性。

当使用查表法时,必须完全消除所有条件判断。操作转换成一个数组项查询或者一个对象成员查询。使用查表法的一个主要优点是:由于没有条件判断,当候选值数量增加时,很少,甚至没有增加额外的性能开销。

查表法最常用于一个键和一个值形成逻辑映射的领域。

在整理JS一些常用的优化方法的同时,总结出来一个理论:写代码在一定的程度上必须要经常回顾语言最本质的特性。原因很简单,起初接触任何一种语言的时候,最先了解的是语言的一些抽象定义。抽象就是简单干练,这也是我们写代码的最终想要达到的程度。


订阅

欢迎订阅AnyForWeb出版物
欢迎订阅伽然出版物

栏目推荐

栏目推荐
JavaScript知识笔记9…

在jQuery源码中我们经常能看见各式各样…

栏目推荐
JavaScript知识笔记8…

函数的调用应该才是函数产生的根本,减…

栏目推荐
JavaScript知识笔记6…

在JS中使用操作符主要用来执行数学、相…

栏目推荐
JavaScript知识笔记5…

周知JS语法相对简单,语言结构简单,这…

栏目推荐
JavaScript知识笔记4…

JS相对于那些所谓重量级语言(C++、C#…

栏目推荐
JavaScript知识笔记3…

Javascript中this是一个指针概念,它表…

栏目推荐
JavaScript知识笔记2…

常见的变成语言Java、C#、C++等,同样…

AnyFroWebUED  

版权所有 © 2009-2016  沪ICP备14026814号-10

 

 

返回

很抱歉!

您现在还没有开通阅读权限,如有疑问,请联系我们。

联系电话:021-52047186

返回