• 性能流程


    性能优化之算法和流程控制

    循环处理是最常见的编程模式之一,也是提升性能必须关注的要点之一。

     

     

     

    常见的优化方案有:

     

     

     

    ①JavaScript的四种循环(for、do-while、while、for-in)中,for-in循环比其他几种明显要慢。由于每次迭代操作会同时搜索实例或原型属性,for-in循环的每次迭代都会产生更多的开销,所以比其他类型要慢。因此遍历一个属性数量有限的已知属性列表,可以这样优化:

     

    1
    2
    3
    4
    var props = ['prop1''prop2'],i = 0;
    whlie(i < props.length){
       precess(object[props[i++]]);
    }

     

    该代码只关注给定的属性,减少了循环的开销。

     

    而对于,for、while、do-while。我在chrome下测试了一下,先创建一个大小为1000000的数组,每项乘100再叠加。

     

    测试用例:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    window.onload = function(){
    var items  = Array(1000000).join(',').split(',').map(function(item, index) {
       return index;
    });
       console.log(forCircle())
       console.log(whileCircle())
       console.log(doCircle())
     
    function forCircle(){
    console.profile();
    var currTime = new Date();
     var tal = 0;
        for(var i = 0;i < items.length; i++){
           tal = tal + process(items[i]);
        }
       console.profileEnd();
       console.log('forCircle用时:' + (new Date() - currTime) + 'ms');
        return tal;
    }
    function whileCircle(){
    console.profile();
    var currTime = new Date();
        var tal = 0;
        var j = 0;
        while (j < items.length){
          tal = tal + process(items[j++]);
        }
       console.profileEnd();
       console.log('whileCircle用时:' + (new Date() - currTime) + 'ms');
        return tal;
    }
    function doCircle(){
    console.profile();
    var currTime = new Date();
       var tal = 0;
       var k = 0;
        do{
            tal = tal + process(items[k++]);
        }while (k < items.length)
           console.profileEnd();
       console.log('doCircle用时:' + (new Date() - currTime) + 'ms');
        return tal;
    }
    function process(item){
        return item*100;
    }
    }

     取某次测试结果:

       

     

    平均来说,for循环耗时8ms,while耗时4ms,doWhile耗时也是4ms。for是最慢的。

     

     

     

    ②减少迭代的工作量。把数组长度保存在局部变量中再遍历、颠倒数组的遍历顺序。

     

    最常见的一个循环:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for(var i = 0;i < items.length; i++){
       process(items[i]);
    }
    //
    var j = 0;
    while (j < items.length){
      process(items[j++]);
    }
    //
    var k = 0;
    do{
        process(items[k++]);
    }while (k < items.length)

    在这个循环中,每次运行都会产生如下操作:

    ①查找一次属性(items.length)

    ②执行数值比较一次(i < items.length) 

    ③查看控制条件是否为true(i < items.length ==true) 

    ④一次自增操作(i++)

    ⑤一次数组查找(items[i])

    ⑥一次函数调用(process(items[i]))

    若把数组长度存到一个局部变量,那么就不需要每次都查找一次items.length,也就提高了性能。

    改为这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    for(var i = 0, len = items.length;i < len; i++){
       process(items[i]);
    }
    //
    var j = 0,
    count = items.length;
    while (j < count){
      process(items[j++]);
    }
    //
    var k = 0,
    num = items.length;
    do{
        process(items[k++]);
    }while (k < num)

      这样在大多数浏览器中能节省大概25%的运行时间(IE中甚至可以节省50%)。总的来说,循环次数大的情况下,运行时间确实有提升。取某次结果如下:

     没有局部存量存储数组长度时:

     

     有局部变量存储数组长度时:

     

    ③减少迭代次数,“Duffs Device”即“达夫设备“循环体展开技术。适合于迭代次数较大的情况下。

     

    摘抄一下书中达夫设备的基本理念:每次循环中最多可 8 次调用 process()函数。循环迭代次数为元素总数除以8。 因为总数不一定是 8的整数倍, 所以 startAt 变量存放余数, 指出第一次循环中应当执行多少次 process()。比方说现在有 12 个元素,那么第一次循环将调用 process()4次,第二次循环调用 process()8 次,用 2 次循环代替了 12次循环。

     

    基本模式:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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); 

      

     

    ④基于函数的迭代比基于循环的迭代消耗性能更多。例:for循环迭代与forEach函数迭代。

     

     

     

    ⑤优化if-else,通常来说,switch比if-else快,但是在判断条件较多时,使用查找表比if-else和switch都快。

     

     

     

    更多测试结论,可参考:http://www.cnblogs.com/hmking/archive/2011/10/10/2205321.html

     

    更多学习可参考《高性能JavaScript》

  • 相关阅读:
    企业移动化?AppCan教你正确的打开方式
    企业该如何挑选移动平台?
    除了移动开发,一个好平台还需要具备什么功能?
    canvas绘制工作流之绘制节点
    canvas与工作流的不解之缘
    一个工作流引擎诞生前的准备工作
    欢迎大家Follow me!微软MVP罗勇(Dynamics CRM方向2015-2018年)欢迎您!
    Dynamics 365定制:在实体的列表界面添加按钮
    Dynamics 365 Customer Engagement中自定义工作流活动的调试
    Dynamics CRM 2015/2016新特性之二十七:使用Web API查询元数据
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/6392150.html
Copyright © 2020-2023  润新知