第四章 Algorithms and Flow Control 算法和流程控制
本章主要讨论算法和流程控制的优化。

第四章 Algorithms and Flow Control 算法和流程控制

  • 在循环中,只有for-in明显比其它的循环要慢。
    由于每次迭代操作要搜索实例或原形的属性,for-in 循环每次迭代都要付出更多开销,所以比其他类型循环慢一些。因此除非需要对不知道数目的对象进行操作,否则尽量避免使用for-in循环。

  • 循环中length局部变量缓存,在上章讨论过,这里不再多说。

    1
    2
    3
    for (var i=0, len=items.length; i < len; i++){
    process(items[i]);
    }
  • 使用达夫设备来减少循环迭代的次数(达夫设备在这里不详细叙述,感兴趣可以自己查资料学习一下)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //credit: Jeff Greenberg
    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);
  • 可以利用二分法优化if-else。 在条件不规则而且很多的情况下,switch要比if-else快一些。

  • 当有大量离散的值需要测试时,尽量使用查表法代替switch或if-else。

    1
    2
    3
    4
    //define the array of results
    var results = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10]
    //return the correct result
    return results[value];
  • 错误的递归会导致长时间的运行,还会遇到浏览器调用栈大小的限制。

  • 使用优化的循环替代长时间运行的递归函数可以提高性能。因为运行一个循环比反复调用一个函数的开销要低。

  • 利用制表来将每次循环或递归的结果缓存,来优化性能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function memfactorial(n){
    if (!memfactorial.cache){
    memfactorial.cache = {
    "0": 1,
    "1": 1
    };
    }
    if (!memfactorial.cache.hasOwnProperty(n)){
    memfactorial.cache[n] = n * memfactorial (n-1);
    }
    return memfactorial.cache[n];

下面代码是封装一个制表的函数。

1
2
3
4
5
6
7
8
9
10
function memoize(fundamental, cache){
cache = cache || {};
var shell = function(arg){
if (!cache.hasOwnProperty(arg)){
cache[arg] = fundamental(arg);
}
return cache[arg];
};
return shell;
}


Summary 总结

  • for,while,do-while 循环的性能特性相似,谁也不比谁更快或更慢。
  • 除非你要迭代遍历一个属性未知的对象,否则不要使用 for-in 循环。
  • 改善循环性能的最好办法是减少每次迭代中的运算量,并减少循环迭代次数。
  • 一般来说,switch 总是比 if-else 更快,但并不总是最好的解决方法。
  • 当判断条件较多时,查表法比 if-else 或者 switch 更快。
  • 浏览器的调用栈尺寸限制了递归算法在 JavaScript 中的应用;栈溢出错误导致其他代码也不能正常执行。
  • 如果你遇到一个栈溢出错误,将方法修改为一个迭代算法或者使用制表法可以避免重复工作。
  • 运行的代码总量越大,使用这些策略所带来的性能提升就越明显。