2016-05-31 43 views
0

我想了解构造数组的性能差异。运行下面的程序,我对下面的输出不解:创建Javascript数组的不同方法

Time for range0: 521 
Time for range1: 149 
Time for range2: 1848 
Time for range3: 8411 
Time for range4: 3487 

我不明白为什么3时间超过4长,同时需要1小于2。此外,似乎映射功能是非常低效的;它有什么用处?


function range0(start, count) { 
 
    var arr = []; 
 
    for (var i = 0; i < count; i++) { 
 
     arr.push(start + i); 
 
    } 
 
    return arr; 
 
} 
 

 
function range1(start, count) { 
 
    var arr = new Array(count); 
 
    for (var i = 0; i < count; i++) { 
 
     arr[i] = start + i; 
 
    } 
 
    return arr; 
 
} 
 

 
function range2(start, count) { 
 
    var arr = Array.apply(0, Array(count)); 
 
    for (var i = 0; i < count; i++) { 
 
     arr[i] = start + i; 
 
    } 
 
    return arr; 
 
} 
 

 
function range3(start, count) { 
 
    var arr = new Array(count); 
 
    return arr.map(function(element, index) { 
 
     return index + start; 
 
    }); 
 
} 
 

 
function range4(start, count) { 
 
    var arr = Array.apply(0, Array(count)); 
 
    return arr.map(function(element, index) { 
 
     return index + start; 
 
    }); 
 
} 
 

 
function profile(range) { 
 
    var iterations = 100000, 
 
     start = 0, count = 1000, 
 
     startTime, endTime, finalTime; 
 

 
    startTime = performance.now(); 
 

 
    for (var i = 0; i < iterations; ++i) { 
 
     range(start, count); 
 
    } 
 

 
    endTime = performance.now(); 
 

 
    finalTime = (endTime - startTime); 
 
    console.log(range.name + ': ' + finalTime + ' ms'); 
 
} 
 

 
[range0, range1, range2, range3, range4].forEach(profile);

+0

现代引擎对预分配的同类阵列进行了优化,因此可能会解释'range1'。 – 2016-05-31 23:39:24

+0

'.map()'存在以接收现有数组并使用潜在的复杂逻辑创建一个具有相同长度的新长度,以确定基于当前成员的每个成员的值。这是一个非常方便的方法。 – 2016-05-31 23:41:10

+0

因为.map()有它自己的工作,因为'var arr = Array.apply(0,Array(count))'是一个非常丑陋的JS指令.. – Redu

回答

1

我不明白为什么3的时间超过4

我也不是。这是一个令人惊讶的结果,考虑到我的表面分析和我通过分析代码获得的结果。在运行Google Chrome 50的计算机上,range4range3慢两倍。

我不得不研究你正在使用的Javascript实现,以便弄清楚为什么会发生这种情况。

而1采取短于2

range1执行得更快,因为它使用一个循环,并优化内存分配,同时,使用range2功能和确实不必要的内存分配。

此外,似乎地图功能是非常低效的;它有什么用处?

map函数用于基于现有值的计算新的Array

[1, 2, 3, 4, 5].map(number => number * number); 
// [1, 4, 9, 16, 25] 

在我的电脑

Time for range0: 783 
Time for range1: 287 
Time for range2: 10541 
Time for range3: 14981 
Time for range4: 28243 

我的结果反映了我对于每个功能的业绩预期。

每个功能

  • range0

    的表面的分析创建一个Array并且经由循环填充。这是最简单直接的代码。我想这可以理解为基线进行性能比较。

  • range1

    采用Array constructor具有长度参数。这极大地优化了存储元素所需的底层内存分配。由于元素的确切数量是事先已知的,因此随着元素数量增长,内存不一定是realloc。当Array被实例化时,存储所有元素所需的确切内存量只能被分配一次。

  • range2

    Applies参数列表的构造函数,用this集的数量0。这在语义上等同于Array() - 使用参数count创建参数列表的事实与函数应用程序的结果无关。实际上,它不必要地浪费时间为空的参数列表分配内存。

    你可能想用的call

    Array.call(null, count) 
    
  • range3

    range1,但有一个功能,而不是循环使用map。初始内存分配已优化,但调用函数count时间的开销可能很大。

    另外,map生成新的Array实例。由于该实例也具有count元素,因此优化内存分配也是有意义的,但是我不清楚这是否真的发生。尽管如此,两个单独的内存分配正在发生,而不是像range1那样只有一个。

  • range4

    结合了range2range3所有的低效率。

    令人惊讶的是,它比您的计算机上的range3执行得更快。我不清楚为什么会发生这种情况。我想你必须调查你的Javascript特定的实现才能搞清楚。

+0

我在nodeJS 4.4.5上运行代码。 nodeJs引擎必须做一些优化来优化range4。我同意Array.apply(null,Array(count))不是创建空数组的正确方法。我从一些样本中复制了代码。绝对应该使用Array.call(null,count)来代替。 – JayL