`

转 高性能JavaScript 循环语句和流程控制

 
阅读更多

众所周知,常用的循环语句有for、while、do-while以及for-in,forEach。除了for-in和forEach性能略低 外,平时我们对前三者的选择更多的是基于需求而非性能考虑,今天我们就对它们各自的性能做个测试,告诉我们最极端的情况下还能做哪些优化。

  首先我们来谈谈为何for-in和forEach会比其他的慢。for-in一般是用在对象属性名的遍历上的,由于每次迭代操作会同时搜索实例 本身的属性以及原型链上的属性,所以效率肯定低下;而forEach是基于函数的迭代(需要特别注意的是所有版本的ie都不支持,如果需要可以用 JQuery等库),对每个数组项调用外部方法所带来的开销是速度慢的主要原因。

  接着我们看看每次迭代中for、while以及do-while都做了什么。

复制代码
var length = items.length;
for(var i = 0; i < length; i++)
  process(items[i]);

var j = 0;
while(j < length) 
  process(items[j++]);

var k = 0;
do {
  process(items[k++]);
} while(k < length);
复制代码

  上面的每个循环中,每次运行循环体时都会产生这样的操作:

  1. 一次控制条件中的数值大小比较(i < length)
  2. 一次控制条件结果是否为true的比较(i < length === true)
  3. 一次自增操作(i++)
  4. 一次数组查找(items[i])
  5. 一次函数调用process(items[i])

  我们可以通过颠倒数组的顺序来提高循环性能:

复制代码
for(var i = items.length; i--; )
  process(items[i]);

var j = items.length;
while(j--) 
  process(items[j]);

var k = items.length - 1;
do {
  process(items[k]);
} while(k--);
复制代码

  本例中使用了倒序循环,并把减法操作整合在循环条件中。现在每个控制条件只是简单地与0比较。控制条件与true值比较,任何非零数会自动转换 为true,而零值等同于false。实际上,控制条件从两个比较(迭代数少于总数吗?它是true吗?)减少到一次比较(它是true吗?)。每次迭代 从两次比较减少到一次,进一步提高了循环速度。

 

性能测试:

  那么事实真的如此吗?真金不怕浏览器验。测试代码很简单,针对不同的8种情况封装了8个函数(不加定时器firefox下无法打印profiles信息,原因不明):

复制代码
// init array
var a = [];
var length = 10;
for(var i = 0; i < length; i++)
  a[i] = 1;

function for_in() {
  var sum = 0;
  for(var i in a) 
    sum += a[i];
}

function for_each() {
  var sum = 0;
  a.forEach(function(value, index, array) {
    sum += value;
  });
}

function for_normal() {
  var sum = 0;
  for(var i = 0; i < length; i++)
    sum += a[i];
}

function for_reverse() {
  var sum = 0;
  for(var i = length; i--; )
    sum += a[i];
}

function while_normal() {
  var sum = 0;
  var i = 0;
  while(i < length) 
    sum += a[i++];
}

function while_reverse() {
  var sum = 0;
  var i = length;
  while(i--) 
    sum += a[i];
}

function do_while_normal() {
  var sum = 0;
  var i = 0;
  do {
    sum += a[i++];
  } while(i < length);
}

function do_while_reverse() {
  var sum = 0;
  var i = length - 1;
  do {
    sum += a[i];
  } while(i--);
}


setTimeout(function() {
  console.profile();
  for_in();
  for_each();
  for_normal();  
  for_reverse();
  while_normal();
  while_reverse();
  do_while_normal();
  do_while_reverse();
  console.profileEnd();
}, 1000);
复制代码

  当数组长度为100时,我们发现firefox下的结果确实和预料的相似:for-each和for-in效率低下,倒序比正序效率略微提升。(chrome下的profiles由于时间太短不显示)

  当数据量达到100w时,firefox和chrome下的结果都如人所愿,但是也略微有所不同。ff下的for-in表现地比for- each好,而chrome下for-in表现糟糕,直接提出了警告。而倒序迭代虽然性能略微有所提升,但是提升的不是很多,且降低了代码阅读性。

 

 小结:

  1. 倒序迭代确实能略微提升代码性能,但是牺牲了代码可读性,除非追求极端性能优化情况下不然没必要用
  2. 遍历数组能用普通的循环就不要用for-in和for-each

条件语句

  常见的条件语句有if-else和switch-case,那么什么时候用if-else,什么时候用switch-case语句呢?

  我们先来看个简单的if-else语句的代码:

复制代码
if (value == 0){
    return result0;
} else if (value == 1){
    return result1;
} else if (value == 2){
    return result2;
} else if (value == 3){
    return result3;
} else if (value == 4){
    return result4;
} else if (value == 5){
    return result5;
} else if (value == 6){
    return result6;
} else if (value == 7){
    return result7;
} else if (value == 8){
    return result8;
} else if (value == 9){
    return result9;
} else {
    return result10;
}
复制代码

  最坏的情况下(value=10)我们可能要做10次判断才能返回正确的结果,那么我们怎么优化这段代码呢?一个显而易见的优化策略是将最可能 的取值提前判断,比如value最可能等于5或者10,那么将这两条判断提前。但是通常情况下我们并不知道(最可能的选择),这时我们可以采取二叉树查找 策略进行性能优化。

复制代码
if (value < 6){
    if (value < 3){
        if (value == 0){
            return result0;
        } else if (value == 1){
            return result1;
        } else {
            return result2;
        }
    } else {
        if (value == 3){
            return result3;
        } else if (value == 4){
            return result4;
        } else {
            return result5;
        }
    }
} else {
    if (value < 8){
        if (value == 6){
            return result6;
        } else {
            return result7;
        }
    } else {
        if (value == 8){
            return result8;
        } else if (value == 9){
            return result9;
        } else {
            return result10;
        }
    }
}
复制代码

  这样优化后我们最多进行4次判断即可,大大提高了代码的性能。这样的优化思想有点类似二分查找,和二分查找相似的是,只有value值是连续的 数字时才能进行这样的优化。但是代码这样写的话不利于维护,如果要增加一个条件,或者多个条件,就要重写很多代码,这时switch-case语句就有了 用武之地。

  将以上代码用switch-case语句重写:

复制代码
switch(value){
    case 0:
        return result0;
    case 1:
        return result1;
    case 2:
        return result2;
    case 3:
        return result3;
    case 4:
        return result4;
    case 5:
        return result5;
    case 6:
        return result6;
    case 7:
        return result7;
    case 8:
        return result8;
    case 9:
        return result9;
    default:
        return result10;
}
复制代码

  swtich-case语句让代码显得可读性更强,而且swtich-case语句还有一个好处是如果多个value值返回同一个结果,就不用 重写return那部分的代码。一般来说,当case数达到一定数量时,swtich-case语句的效率是比if-else高的,因为switch- case采用了branch table(分支表)索引来进行优化,当然各浏览器的优化程度也不一样。

  除了if-else和swtich-case外,我们还可以采用查找表。

var results = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];

//return the correct result
return results[value];

  当数据量很大的时候,查找表的效率通常要比if-else语句和swtich-case语句高,查找表能用数字和字符串作为索引,而如果是字符 串的情况下,最好用对象来代替数组。当然查找表的使用是有局限性的,每个case对应的结果只能是一个取值而不能是一系列的操作。

 

小结:

  1. 当只有两个case或者case的value取值是一段连续的数字的时候,我们可以选择if-else语句
  2. 当有3~10个case数并且case的value取值非线性的时候,我们可以选择switch-case语句
  3. 当case数达到10个以上并且每次的结果只是一个取值而不是额外的JavaScript语句的时候,我们可以选择查找表 
分享到:
评论

相关推荐

    JavaScript语言精粹(高清电子版)和高性能JavaScript 双语版

    1. **基础语法**:包括变量、数据类型、运算符、流程控制语句(如if-else、switch、for循环和while循环)以及函数定义和调用。 2. **作用域和闭包**:讲解了如何管理变量的作用域,以及闭包如何为JavaScript提供...

    高性能JavaScript.pdf

    - **流程控制**:使用条件语句、循环等语法结构来控制程序的执行流程。 **技术细节:** - 在JavaScript中,合理的算法设计可以显著提高程序性能。 - 循环、递归等基本流程控制结构的应用技巧对于优化代码至关重要。...

    高性能JavaScript编程1

    本章涵盖了基础算法和流程控制结构,如循环、条件语句等,以及它们在JavaScript中的实现。讨论了如何优化循环性能,避免不必要的计算,以及合理选择控制流工具来提高代码执行效率。 第五章 “字符串和正则表达式”...

    高性能JavaScript编程

    通过阅读《高性能JavaScript编程》中英对照版和英文版,开发者可以全面提升对JavaScript性能优化的理解,为构建更快、更稳定的Web应用打下坚实基础。无论是初级开发者还是经验丰富的专业人士,这本书都能提供宝贵的...

    高性能JavaScript_编程_javascript_js_

    1. **基础语法与数据类型**:JavaScript的基础包括变量、数据类型(如基本类型和引用类型)、操作符、流程控制语句以及函数。理解这些概念对于编写高效代码至关重要。 2. **作用域和闭包**:了解JavaScript的作用域...

    JavaScript常用107个语句

    4. **流程控制**:`if...else`用于条件判断,`for`、`while`用于循环,`switch...case`处理多分支选择。 5. **函数**:`function`关键字用于定义函数,可以有参数和返回值。ES6新增了箭头函数(`=&gt;`),语法更简洁...

    JavaScript高级编程 pdf

    10. **性能优化**:理解V8引擎的工作原理,学习如何编写高性能的JavaScript代码,如减少内存泄漏、优化循环等。 11. **ES6新特性**:箭头函数、类、解构赋值、模板字符串、let/const、生成器、async/await等,这些...

    JavaScript前端开发程序设计教程(微课版)-PPT课件.zip

    JavaScript作为Web开发中的重要语言,是前端开发的核心技术之一,尤其在构建动态、交互式的...通过系统学习,开发者不仅能理解JavaScript的核心原理,还能运用到实际项目中,打造出具有高性能和良好用户体验的Web应用。

    JavaScript程序设计基础教程(慕课版)_PPT详细版.zip

    1. **基础概念**:讲解JavaScript的基本语法,如变量、数据类型(包括基本类型和引用类型)、运算符、流程控制(条件语句和循环语句)以及函数的使用。 2. **对象与数组**:深入理解JavaScript的对象机制,包括属性...

    JavaScript脚本程序设计

    JavaScript的基础包括变量声明(var、let、const)、数据类型(如字符串、数字、布尔值、null、undefined、对象、数组、符号、大整数)、运算符(算术、比较、逻辑、位运算、三元运算)、流程控制(条件语句、循环...

    JavaScript高级教程(完整版)

    首先,JavaScript的基础部分涵盖了变量、数据类型(包括基本类型和引用类型)、操作符、流程控制(如条件语句和循环)、函数以及作用域。理解这些基础知识对于编写任何JavaScript代码都是至关重要的。变量用于存储...

    javascript 高级程序设计

    书中首先会讲解JavaScript的基本语法,包括变量、数据类型、运算符、流程控制(条件语句与循环)以及函数。这些基础知识构成了JavaScript程序的基础结构,为后续的高级主题打下坚实的基础。 接下来,深入到对象和...

    JAVAscript高级教程_程序设计

    接着,我们将讨论JavaScript的控制结构,包括条件语句(如if...else和switch)和循环(如for、while和do...while),它们是程序逻辑的基础。同时,了解函数的定义与调用,特别是箭头函数和闭包,能帮助你编写更加...

    JavaScript小程序

    2. **控制结构**:JavaScript提供了条件语句(if...else)和循环语句(for、while、do...while)来控制程序的流程。这些结构在编写游戏逻辑时起着关键作用。 3. **函数**:函数是一段可重复使用的代码块,可以接受...

    javascript高级教程

    1. **基础语法**:包括变量声明(var、let、const)、数据类型(如字符串、数字、布尔值、null、undefined、对象、数组等)、运算符、流程控制(条件语句、循环语句)。 2. **函数与闭包**:函数作为第一类公民,...

    使用JavaScript+CSS实现翻转魔方.rar

    - 控制流程:包括条件语句(if...else)和循环(for、while),用于处理程序逻辑。 - 函数:定义和调用函数,是代码复用的基础。 - DOM操作:JavaScript可以用于操作HTML文档对象模型(DOM),例如修改元素内容、...

    程序天下:JavaScript实例自学手册PDF

    2. **基础语法**:JavaScript的基础包括变量声明(var、let、const)、数据类型(如字符串、数字、布尔、null、undefined)、操作符(算术、比较、逻辑)、流程控制(条件语句if...else、循环for、while等)。...

    JavaScript高级程序设计第四版-示例代码

    1. **基础语法**:变量声明(var, let, const)、数据类型(原始类型和引用类型)、运算符(算术、比较、逻辑、三元)、流程控制(条件语句、循环语句、开关语句)、函数(声明式与表达式、作用域、闭包)等。...

    javascript语言精粹 pdf

    此外,流程控制语句(如if...else、for、while)帮助我们根据条件执行不同的代码块,实现程序的逻辑流程。 接着,深入学习函数和对象。JavaScript中的函数不仅是代码的复用单元,还可以作为值传递,甚至可以作为...

    JavaScript权威指南(JavaScript犀牛书一本)

    1. **基础语法**:讲解了变量、数据类型、运算符、流程控制(如条件语句、循环)、函数等基本元素,帮助初学者建立JavaScript编程的基本框架。 2. **对象和原型**:深入探讨了JavaScript的面向对象特性,包括对象...

Global site tag (gtag.js) - Google Analytics