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

问题描述 投票:221回答:22

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

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

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

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

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

我只是想知道哪种是最好的练习方式?

javascript performance loops
22个回答
311
投票

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

http://jsben.ch/y3SpC

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

带有长度缓存的循环标准

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

}

我想说这肯定是我鼓励JavaScript引擎开发人员的情况。应该优化运行时间以保持清晰,而不是聪明。


6
投票

这个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***

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


4
投票

这是2017年。

我做了一些测试。

looks to be the fastest way

看起来var el; while (el = arr.shift()) { el *= 2; } 方法是Chrome上最快的方法。

在Firefox上看起来左减量(https://jsperf.com/fastest-way-to-iterate-through-an-array/)比其他(while--i++i)要快得多。

这种方法平均速度最快。但它以相反的顺序迭代数组。

i--

如果远期订单很重要,请使用此方法。

i++

2
投票

我总是写第一种风格。

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

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


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

i ++比++ i, - i和i更快 -

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

你可以在这里测试它(使用其他循环测试):let ii = array.length; let i = 0; while (i < ii) { doSomething(array[i]); ++i; }


0
投票

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

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

0
投票

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

http://jsperf.com/for-vs-whilepop/5

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

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


0
投票

另一个jsperf.com测试: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++; } }

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


0
投票

截至2017年9月,http://jsfiddle.net/tejzpr/bbLgzxgo/在Chrome 60上展示了以下最高性能模式:

http://jsperf.com/while-reverse-vs-for-cached-length

有人能够复制吗?


0
投票

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

these jsperf tests


0
投票

虽然循环比循环快一点。

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

请改用while循环


83
投票

循环遍历javascript数组的绝对最快方法是:

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

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



-1
投票

在数组中循环的更快方法是使用过滤器。 filter()方法创建一个新数组,其中包含所有传递由提供的函数实现的测试的元素。

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

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

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


-1
投票

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

我们还有https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter,它使WebWorker更容易用于数据处理。


33
投票

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

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

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

  • 如果您的应用程序迭代了很多项目,或者您的循环代码位于经常使用的函数中,那么直接的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] }

28
投票

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

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

它可以缓存长度,写入时间要短得多。但它会以相反的顺序迭代数组。


22
投票

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

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

arr.forEach( a => {
  // ...
}

因为你可以看到很多像for(a = 0; ... )这样的for-loop然后值得一提的是,如果没有'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;
  });
}]
, ["for..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( const a in ar ) {
    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>

19
投票

2014年While又回来了

只是思考逻辑。

看这个

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

 //do stuff

}
  1. 需要创建至少2个变量(索引,长度)
  2. 需要检查索引是否小于长度
  3. 需要增加指数
  4. for循环有3个参数

现在告诉我为什么这应该比以下更快:

var length = array.length;

while( --length ) { //or length--

 //do stuff

}
  1. 一个变量
  2. 没有检查
  3. 指数下降(机器更喜欢)
  4. while只有一个参数

当Chrome 28显示for循环比while更快时,我完全感到困惑。这必须有某种程度

“呃,每个人都在使用for循环,让我们在开发chrome时专注于它。”

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

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

你不能在jsperf上获得while循环的实际速度。

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

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

真正的问题实际上是dom操纵/渲染时间/绘图时间,或者你想要调用它。

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

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

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

注意参数的设置:

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

说,这证实了机器喜欢 -

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

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

即使它更短,看起来使用i再一次减慢一切。它比之前的for循环和while循环慢了1/5。

注意:在没有qazxsw poi的for循环之后,qazxsw poi非常重要

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

;

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

{}

这个答案是为了展示编写javascript的高效方法。因此,如果您无法阅读,请询问并获得答案或阅读有关javascript http://jsperf.com/caching-array-length/40的书籍


11
投票

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

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

缓存长度不是那么重要,但它并没有害处。

上面链接的每个第一次测试(在新打开的选项卡上)在我的Debian Squeeze 64位(http://www.ecma-international.org/ecma-262/5.1/)中的Chrome,Opera和Firefox中的最后4个片段(图表中的第3,第5,第7和第10)给出了最佳结果。后续运行给出了完全不同的结果。

性能方面的结论很简单:


tl;博士

如今(2011.10)下面的模式看起来是最快的。

<

请注意缓存shift()在这里并不重要,所以你可以测试for (var i = 0, len = arr.length; i !== len; i++) { ... } 并且性能不会下降,但你会得到更短的代码。


PS:我知道在使用arr.length的片段中,它的结果可以用来代替访问第0个元素,但是我在某种程度上忽略了重用之前的修订版(它有错误的while循环),后来我不想丢失已经获得的结果。


8
投票

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

纯粹的性能“最好”是这个,它使用缓存和++前缀运算符(我的数据:i !== arr.length

shift()

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

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

7
投票

**缓存循环内的数组长度,几秒钟的时间将被躲避。如果数组中有更多项目,那么取决于数组中的项目,与时间的Ms *有很大的不同

**

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

**

**

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

**

© www.soinside.com 2019 - 2024. All rights reserved.