在JavaScript中循环数组的最快方法是什么?

时间:2011-03-18 08:05:06

标签: javascript performance loops

我从书中了解到你应该写这样的循环:

for(var i=0, len=arr.length; i < len; i++){
    // blah blah
}

因此每次都不会计算arr.length

其他人说编译器会对此做一些优化,所以你可以写:

for(var i=0; i < arr.length; i++){
    // blah blah
}

我只想知道哪种方式最好?

24 个答案:

答案 0 :(得分:306)

使用大多数现代浏览器执行此测试后......

http://jsben.ch/y3SpC

目前 ,最快的循环形式(在我看来,语法最明显)。

带有长度缓存的循环标准

for (var i = 0, len = myArray.length; i < len; i++) {

}

我想说这肯定是我赞扬JavaScript引擎开发人员的情况。运行时间应针对清晰度进行优化,不要聪明

答案 1 :(得分:83)

循环访问javascript数组的绝对最快方法是:

var len = arr.length;
while (len--) {
    // blah blah
}

请参阅http://blogs.oracle.com/greimer/entry/best_way_to_code_a进行完整比较

答案 2 :(得分:33)

截至2016年6月,在最新的Chrome中进行一些测试(2016年5月浏览器市场的71%,并且还在增加):

  • 最快的循环是for循环,无论是否有缓存长度,都能提供非常相似的性能。 (缓存长度的for循环有时会提供比没有缓存的for循环更好的结果,但差异几乎可以忽略不计,这意味着引擎可能已经过优化以支持标准,并且可能最简单的循环而没有缓存)。
  • 减少的while循环比for循环慢约1.5倍。
  • 使用回调函数(如标准forEach)的循环比for循环慢大约10倍。

我认为这个线程太旧了,误导程序员认为他们需要缓存长度,或者使用带有减量的反向遍历来实现更好的性能,编写代码不太简单且更容易出错而不是简单直截了当for循环。因此,我建议:

  • 如果您的应用程序迭代了很多项目,或者您的循环代码位于经常使用的函数中,那么直接的循环就是答案:

    for (var i = 0; i < arr.length; i++) {
      // Do stuff with arr[i] or i
    }
    
  • 如果您的应用程序没有真正遍历大量项目,或者您只需要在此处进行小型迭代,则使用标准forEach回调或您选择的JS库中的任何类似函数可能更容易理解,不太容易出错,因为索引变量范围已关闭,您不需要使用括号,直接访问数组值:

    arr.forEach(function(value, index) {
      // Do stuff with value or index
    });
    
  • 如果您在迭代数十亿行时确实需要花几毫秒时间,并且数组的长度不会在整个过程中发生变化,您可以考虑在for循环中缓存长度。虽然我认为现在真的没有必要:

    for (var i = 0, len = arr.length; i < len; i++) {
      // Do stuff with arr[i]
    }
    

答案 3 :(得分:28)

如果订单不重要,我更喜欢这种风格:

for(var i = array.length; i--; )

它缓存长度并且写得更短。但它会以相反的顺序迭代数组。

答案 4 :(得分:22)

这只是2018年所以更新可能会很好......

我真的必须不同意接受的答案。 它在不同的浏览器上推迟。有些forEach更快,有些for-loop,有些while 这是所有方法http://jsben.ch/mW36e

的基准
arr.forEach( a => {
  // ...
}

因为你可以看到很多类似于for(a = 0; ... )的for循环,所以值得一提的是,没有'var'变量将全局定义,这会极大地影响速度,所以它会变慢。

var arr = arr = new Array(11111111).fill(255);
var benches =     
[ [ "empty", () => {
  for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
  for(var a = 0, l = arr.length; a < l; ++a)
    var b = arr[a] + 1;
}]
, ["for-loop++", () => {
  for(var a = 0, l = arr.length; a < l; a++)
    var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
  for(var a = 0; a < arr.length; ++a )
    var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
  for(var a = arr.length - 1; a >= 0; --a )
    var b = arr[a] + 1;
}]
,["while-loop", () => {
  var a = 0, l = arr.length;
  while( a < l ) {
    var b = arr[a] + 1;
    ++a;
  }
}]
, ["reverse-do-while-loop", () => {
  var a = arr.length - 1; // CAREFUL
  do {
    var b = arr[a] + 1;
  } while(a--);   
}]
, ["forEach", () => {
  arr.forEach( a => {
    var b = a + 1;
  });
}]
, ["Duff's device", () => {
  var i = 0;
  var r = arr.length % 8;
  var n = (arr.length - r) / 8;
  if (r > 0) do {
      var b = arr[i++] + 1;
    }
    while (--r);
  if (n > 0) do {
      var b = arr[i] + 1;
      var c = arr[i+1] + 1;
      var d = arr[i+2] + 1;
      var e = arr[i+3] + 1;
      var f = arr[i+4] + 1;
      var g = arr[i+5] + 1;
      var h = arr[i+6] + 1;
      var k = arr[i+7] + 1;
      i = --n >>> 3;
    }
    while (n);
}]
, ["Duff's device negative", () => {
  var r = arr.length % 8;
  var n = (arr.length-r) / 8; ///Math.floor(arr.length / 8);
  var i	= arr.length ; // -1;

  while(r){
    var b = arr[--i] + 1;
    --r;
  }

  while(n){
      var b = arr[i] + 1;
      var c = arr[i-1] + 1;
      var d = arr[i-2] + 1;
      var e = arr[i-3] + 1;
      var f = arr[i-4] + 1;
      var g = arr[i-5] + 1;
      var h = arr[i-6] + 1;
      var j = arr[i-7] + 1;
      i = --n >>> 3;
  }
}]];
function bench(title, f) {
  var t0 = performance.now();
  var res = f();
  return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
  // Here if you forget to put 'var' so variables'll be global
  for(a = 0, l = arr.length; a < l; ++a)
     var b = arr[a] + 1;
});
var times = benches.map( function(a) {
                      arr = new Array(11111111).fill(255);
                      return [a[0], bench(...a)]
                     }).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
  `<div>` +
    `<span>${title} &nbsp;</span>` +
    `<span style="width:${3+n/2}%">&nbsp;${Number(time.toFixed(3))}msec</span>` +
  `</div>`;

var strRes = times.map( t => template(...t) ).join("\n") + 
            `<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div {  clear:both   }
body > div > div > span {
  float:left;
  width:43%;
  margin:3px 0;
  text-align:right;
}
body > div > div > span:nth-child(2) {
  text-align:left;
  background:darkorange;
  animation:showup .37s .111s;
  -webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>

答案 5 :(得分:19)

2014年While又回来了

认真思考。

请看这个

for( var index = 0 , length = array.length ; index < length ; index++ ) {

 //do stuff

}
  1. 需要创建至少2个变量(索引,长度)
  2. 需要检查索引是否小于长度
  3. 需要增加索引
  4. for循环有3个参数
  5. 现在告诉我为什么这应该比以下更快:

    var length = array.length;
    
    while( --length ) { //or length--
    
     //do stuff
    
    }
    
    1. 一个变量
    2. 没有支票
    3. 指数降低(机器更喜欢)
    4. while只有一个参数
    5. 当Chrome 28显示for循环比while更快时,我完全感到困惑。 这必须有某种

      &#34;呃,每个人都在使用for循环,让我们专注于那个  为chrome开发。&#34;

      但是现在,2014年,while循环重新开始使用chrome。它的速度提高了2倍,在其他/旧浏览器上它总是更快。

      最近我做了一些新的测试。现在在现实世界中,这些短代码是没有价值的,而jsperf实际上无法正确执行while循环,因为它需要重新创建array.length,这也需要时间。

      你可以在jsperf上获得while循环的实际速度。

      您需要创建自己的自定义函数,并使用window.performance.now()

      进行检查

      是的......没有办法让while循环更快。

        

      真正的问题实际上是dom操纵/渲染时间/   抽出时间或者你想要打电话。

      例如,我有一个画布场景,我需要计算坐标和碰撞......这是在10-200 MicroSeconds(非毫秒)之间完成的。它实际上需要几毫秒才能呈现所有内容。如DOM中那样。

      <强> BUT

      在某些情况下还有另一种使用for loop的超级高效方式...例如复制/克隆数组

      for(
       var i = array.length ;
       i > 0 ;
       arrayCopy[ --i ] = array[ i ] // doing stuff
      );
      

      注意参数的设置:

      1. 与while循环相同,我只使用一个变量
      2. 需要检查索引是否大于0;
      3. 正如你所看到的那样,这个方法与每个人使用的正常循环不同,因为我在第3个参数内做了东西,而且我也直接在数组内部减少。
      4. 说,这证实了像

        这样的机器

        写这篇文章我想把它缩短一点并删除一些无用的东西并用同样的风格写下这个:

        for(
         var i = array.length ;
         i-- ;
         arrayCopy[ i ] = array[ i ] // doing stuff
        );
        

        即使它更短,看起来使用i还有一次会减慢一切。 它比前一个for循环和while循环慢1/5。

        注意: ;在没有{}的for looo之后非常重要

        即使我刚刚告诉你jsperf不是测试脚本的最好方法..我在这里添加了这2个循环

        http://jsperf.com/caching-array-length/40

        这是另一个关于javascript性能的答案

        https://stackoverflow.com/a/21353032/2450730

        这个答案是为了展示编写javascript的高效方法。因此,如果您无法阅读,请询问并获得答案或阅读有关javascript http://www.ecma-international.org/ecma-262/5.1/

        的书籍

答案 6 :(得分:11)

http://jsperf.com/caching-array-length/60

我准备的最新版测试(通过重用旧版本)显示了一件事。

缓存长度并不重要,但不会造成伤害。

上面链接的每个第一次测试(在新打开的标签页上)都会在我的Debian Squeeze 64位中为Chrome,Opera和Firefox中的最后4个片段(图表中的第3,第5,第7和第10个)提供最佳结果( my desktop hardware)。后续运行会产生完全不同的结果。

表现明智的结论很简单:

  • 转到for循环(转发)并使用!==代替<进行测试。
  • 如果您以后不必重复使用该数组,那么while循环减少长度和破坏性shift() - 数组也很有效。

TL;博士

现在(2011.10)下面的模式看起来是最快的。

for (var i = 0, len = arr.length; i !== len; i++) {
    ...
}

请注意,缓存arr.length在这里并不重要,因此您只需测试i !== arr.length并且性能不会下降,但您将获得更短的代码。


PS:我知道在使用shift()的代码段中,可以使用其结果而不是访问第0个元素,但是我在某种程度上忽略了重用之前的修订版(其中包含错误的while循环),后来我没有想要失去已经获得的结果。

答案 7 :(得分:8)

纯粹表现中的“最佳”?或表现 AND 可读性?

纯性能“最佳”就是这个,它使用缓存和++前缀运算符(我的数据:http://jsperf.com/caching-array-length/189

for (var i = 0, len = myArray.length; i < len; ++i) {
  // blah blah
}

我认为无缓存for循环是执行时间和程序员阅读时间的最佳平衡。每个以C / C ++ / Java开头的程序员都不会浪费ms必须通读这个

for(var i=0; i < arr.length; i++){
  // blah blah
}

答案 8 :(得分:6)

到目前为止looks to be the fastest way ......

var el;
while (el = arr.shift()) {
  el *= 2;
}

考虑到这将消耗阵列,吃掉它,不留任何东西......

答案 9 :(得分:6)

**缓存循环内的数组长度,几秒钟的时间将被忽略。如果数组中有更多项目,那么取决于数组中的项目,与时间的Ms *存在重大差异*

**

sArr; //Array[158];

for(var i = 0 ; i <sArr.length ; i++) {
 callArray(sArr[i]); //function call
}

***end: 6.875ms***

**

**

sArr; //Array[158];
for(var i = 0,len = sArr.length ; i < len ; i++) {
  callArray(sArr[i]); //function call
}

***end: 1.354ms***

**

答案 10 :(得分:4)

2017年

我做了一些测试。

https://jsperf.com/fastest-way-to-iterate-through-an-array/

看起来while方法在Chrome上速度最快。

看起来左侧减量(--i)比Firefox上的其他减量(++ii--i++)快得多。

这种方法平均禁食。但它以相反的顺序迭代数组。

let i = array.length;
while (--i >= 0) {
    doSomething(array[i]);
}

如果正向订单很重要,请使用此方法。

let ii = array.length;
let i = 0;
while (i < ii) {
    doSomething(array[i]);
    ++i;
}

答案 11 :(得分:2)

我总是以第一种风格写作。

即使编译器足够聪明以便为数组进行优化,但如果我们在这里使用DOMNodeList或者计算长度的某个复杂对象,它仍然很聪明吗?

我知道关于数组的问题是什么,但我认为用一种风格编写所有循环是个好习惯。

答案 12 :(得分:1)

var arr = []; // The array
var i = 0;
while (i < arr.length) {
    // Do something with arr[i]
    i++;
}

i ++比++ i, - i和i -

更快

此外,您可以在上次需要访问i时保存最后一行arr [i ++](但这可能很难调试)。

您可以在此处测试(使用其他循环测试):http://jsperf.com/for-vs-whilepop/5

答案 13 :(得分:0)

我已经尝试了一些其他方法来迭代一个巨大的数组,并发现将数组长度减半然后在单个循环中迭代两半更快。处理巨大数组时可以看到这种性能差异。

var firstHalfLen =0;
var secondHalfLen = 0;
var count2=0;
var searchterm = "face";
var halfLen = arrayLength/2;
if(arrayLength%2==halfLen)
{
   firstHalfLen = Math.ceil(halfLen);
   secondHalfLen=Math.floor(halfLen);
}
else
{
   firstHalfLen=halfLen;
   secondHalfLen=halfLen;
}
for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen;
    firstHalfCOunter < firstHalfLen;
    firstHalfCOunter++)
{
  if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1)
  {
    count2+=1;
  }
  if(secondHalfCounter < arrayLength)
  {
    if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1)
    {
        count2+=1;
    }
    secondHalfCounter++; 
  }
}

缓存长度for-loop与上述方法之间的一些性能比较(使用timer.js)。

http://jsfiddle.net/tejzpr/bbLgzxgo/

答案 14 :(得分:0)

另一个jsperf.com测试:http://jsperf.com/while-reverse-vs-for-cached-length

反向while循环似乎是最快的。唯一的问题是,虽然(--i)将停在0.如何在循环中访问数组[0]呢?

答案 15 :(得分:0)

截至2017年9月,these jsperf tests显示以下模式在Chrome 60上效果最佳:

function foo(x) {
 x;
};
arr.forEach(foo);

有人能够复制吗?

答案 16 :(得分:0)

基本的while循环通常是最快的。 jsperf.com是一个很好的沙箱来测试这些类型的概念。

https://jsperf.com/fastest-array-loops-in-javascript/24

答案 17 :(得分:0)

我所知道的最优雅的解决方案是使用地图。

var arr = [1,2,3];
arr.map(function(input){console.log(input);});

答案 18 :(得分:0)

while循环比循环快一点。

var len = arr.length;
while (len--) {
    // blah blah
}

使用while循环

答案 19 :(得分:0)

尝试一下:

var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}

答案 20 :(得分:0)

截至2019年,WebWorker变得越来越流行,对于大型数据集,我们可以使用WebWorker通过充分利用多核处理器来更快地处理数据。

我们还有Parallel.js,它使WebWorker更加易于用于数据处理。

答案 21 :(得分:0)

最快的方法是传统的for循环。这是更全面的性能比较。

https://gists.cwidanage.com/2019/11/how-to-iterate-over-javascript-arrays.html

答案 22 :(得分:0)

如果您想要更快的 for 循环,请在循环之外定义变量并使用以下语法

expression='to_entries | map("\(.key)=\(.value | @sh)") | .[]'

参考:https://medium.com/kbdev/voyage-to-the-most-efficient-loop-in-nodejs-and-a-bit-js-5961d4524c2e

答案 23 :(得分:-1)

在数组中循环的更快方法是使用过滤器。 filter()方法创建一个新数组,其中所有元素都通过了由提供的功能实现的测试。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

const words = ['Floccinaucinihilipilification', 'limit', 'elite', 'Hippopotomonstrosesquipedaliophobia', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(new Date(), result);

根据我的经验,我总是更喜欢过滤器,地图等。