建议21:推荐提高循环性能的策略(1)
每次运行循环体时都会产生性能开销,增加总的运行时间,即使是循环体中最快的代码,累计迭代上千次,也将带来不小的负担。因此,减少循环的迭代次数可获得显著的性能提升。例如:
- var iterations = Math.floor(items.length / 8), startAt = items.length % 8, i = 0;
- do {
- switch(startAt) {
- case 0:
- process(items[i++]);
- case 7:
- process(items[i++]);
- case 6:
- process(items[i++]);
- case 5:
- process(items[i++]);
- case 4:
- process(items[i++]);
- case 3:
- process(items[i++]);
- case 2:
- process(items[i++]);
- case 1:
- process(items[i++]);
- }
- startAt = 0;
- } while (--iterations);
在上面代码中,每次循环最多可调用process()函数8次。循环迭代次数为元素总数除以8。因为总数不一定是8的整数倍,所以startAt变量存放余数,指明第一次循环中应当执行多少次process()。如果现在有12个元素,那么第一次循环将调用process() 4次,第二次循环调用process() 8次,用两次循环代替了12 次循环。在下面的代码中取消switch 表达式,将余数处理与主循环分开。 - var i = items.length % 8;
- while(i) {
- process(items[i--]);
- }
- i = Math.floor(items.length / 8);
- while(i) {
- process(items[i--]);
- process(items[i--]);
- process(items[i--]);
- process(items[i--]);
- process(items[i--]);
- process(items[i--]);
- process(items[i--]);
- process(items[i--]);
- }
虽然上面代码使用两个循环替代了先前的一个循环,但是在循环体中去掉了switch 表达式,速度更快。如果循环的迭代次数少于1000次,减少迭代次数的循环与普通循环相比可能只有微不足道的性能提升。如果迭代次数超过1000 次,比如在500 000 次迭代中,合理地减少循环的迭代次数可以使运行时间减少到普通循环的70%。
有两个因素影响到循环的性能:
每次迭代干什么。
迭代的次数。
通过减少这两者中的一个或全部(的执行时间),可以提高循环的整体性能。如果一次循环需要较长时间来执行,那么多次循环将需要更长时间。限制在循环体内进行耗时操作的数量是一个加快循环的好方法。一个典型的数组处理循环可采用3种循环的任何一种。最常用的代码如下:
- //方法1
- for (var i=0; i < items.length; i++){
- process(items[i]);
- }
- //方法2
- var j=0;
- while (j < items.length){
- process(items[j++]);
- }
- //方法3
- var k=0;
- do {
- process(items[k++]);
- } while (k < items.length);