在 JavaScript 中循环数组的最快方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5349425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the fastest way to loop through an array in JavaScript?
提问by wong2
I learned from books that you should write for loop like this:
我从书上知道你应该像这样写 for 循环:
for(var i=0, len=arr.length; i < len; i++){
// blah blah
}
so the arr.length
will not be calculated each time.
所以arr.length
不会每次都计算。
Others say that the compiler will do some optimization to this, so you can just write:
其他人说编译器会对此做一些优化,所以你可以这样写:
for(var i=0; i < arr.length; i++){
// blah blah
}
I just want to know which is the best way in practice?
我只想知道实践中哪种方法最好?
回答by jondavidjohn
After performing this test with most modern browsers...
在使用大多数现代浏览器执行此测试后...
Currently, the fastest form of loop (and in my opinion the most syntactically obvious).
目前,最快的循环形式(在我看来是最明显的句法)。
a standard for loop with length caching
具有长度缓存的循环标准
for (var i = 0, len = myArray.length; i < len; i++) {
}
I would say this is definitely a case where I applaud JavaScript engine developers. A run time should be optimized for clarity, not cleverness.
我会说这绝对是我为 JavaScript 引擎开发人员鼓掌的一个案例。运行时应该优化为清晰,而不是聪明。
回答by gnur
The absolute fastest way to loop through a javascript array is:
循环遍历 javascript 数组的绝对最快方法是:
var len = arr.length;
while (len--) {
// blah blah
}
See http://blogs.oracle.com/greimer/entry/best_way_to_code_afor a full comparison
有关完整比较,请参阅http://blogs.oracle.com/greimer/entry/best_way_to_code_a
回答by CGodo
As of June 2016, doing some tests in latest Chrome (71% of the browser market in May 2016, and increasing):
截至 2016 年 6 月,在最新的 Chrome 中进行了一些测试(2016 年 5 月浏览器市场的 71%,并且还在增加):
- The fastest loop is a for loop, both with and without caching length delivering really similar performance. (The for loop with cached length sometimes delivered better results than the one without caching, but the difference is almost negligible, which means the engine might be already optimized to favor the standard and probably most straightforward for loop without caching).
- The while loop with decrements was approximately 1.5 times slower than the for loop.
- A loop using a callback function (like the standard forEach), was approximately 10 times slower than the for loop.
- 最快的循环是 for 循环,无论有没有缓存长度都提供非常相似的性能。(具有缓存长度的 for 循环有时比没有缓存的 for 循环提供更好的结果,但差异几乎可以忽略不计,这意味着引擎可能已经进行了优化以支持标准并且可能是最直接的没有缓存的 for 循环)。
- 带有递减的 while 循环比 for 循环慢大约 1.5 倍。
- 使用回调函数(如标准 forEach)的循环比 for 循环慢大约 10 倍。
I believe this thread is too old and it is misleading programmers to think they need to cache length, or use reverse traversing whiles with decrements to achieve better performance, writing code that is less legible and more prone to errors than a simple straightforward for loop. Therefore, I recommend:
我认为这个线程太旧了,它误导程序员认为他们需要缓存长度,或者使用带有递减的反向遍历 whiles 来获得更好的性能,编写比简单直接的 for 循环更易读且更容易出错的代码。因此,我建议:
If your app iterates over a lot of items or your loop code is inside a function that is used often, a straightforward for loop is the answer:
for (var i = 0; i < arr.length; i++) { // Do stuff with arr[i] or i }
If your app doesn't really iterate through lots of items or you just need to do small iterations here and there, using the standard forEach callback or any similar function from your JS library of choice might be more understandable and less prone to errors, since index variable scope is closed and you don't need to use brackets, accessing the array value directly:
arr.forEach(function(value, index) { // Do stuff with value or index });
If you really need to scratch a few milliseconds while iterating over billions of rows and the length of your array doesn't change through the process, you might consider caching the length in your for loop. Although I think this is really not necessary nowadays:
for (var i = 0, len = arr.length; i < len; i++) { // Do stuff with arr[i] }
如果您的应用程序迭代大量项目,或者您的循环代码位于经常使用的函数中,那么简单的 for 循环就是答案:
for (var i = 0; i < arr.length; i++) { // Do stuff with arr[i] or i }
如果您的应用程序并没有真正迭代大量项目,或者您只需要在这里和那里进行小规模迭代,那么使用标准 forEach 回调或您选择的 JS 库中的任何类似函数可能更容易理解且不易出错,因为index 变量作用域是关闭的,不需要使用方括号,直接访问数组值:
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] }
回答by Felix Kling
If the order is not important, I prefer this style:
如果顺序不重要,我更喜欢这种风格:
for(var i = array.length; i--; )
It caches the length and is much shorter to write. But it will iterate over the array in reverse order.
它缓存长度并且写入要短得多。但它会以相反的顺序遍历数组。
回答by nullqube
It's just 2018 so an update could be nice...
现在是 2018 年,所以更新可能会很好......
And I really have to disagree with the accepted answer.
It defers on different browsers. some do forEach
faster, some for-loop
, and some while
here is a benchmark on all method http://jsben.ch/mW36e
我真的不得不不同意接受的答案。它在不同的浏览器上有所延迟。有的做forEach
快,有的for-loop
,有的while
在这里是所有方法的基准http://jsben.ch/mW36e
arr.forEach( a => {
// ...
}
and since you can see alot of for-loop like for(a = 0; ... )
then worth to mention that without 'var' variables will be define globally and this can dramatically affects on speed so it'll get slow.
并且因为您可以看到很多像这样的 for 循环,for(a = 0; ... )
所以值得一提的是,如果没有 '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 const..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( const a in ar ) {
var b = a + 1;
}
}]
, ["for let..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( let a in ar ) {
var b = a + 1;
}
}]
, ["for var..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( var 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} </span>` +
`<span style="width:${3+n/2}%"> ${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>
回答by cocco
2014 While
is back
2014While
又回来了
Just think logical.
只是想合乎逻辑。
Look at this
看这个
for( var index = 0 , length = array.length ; index < length ; index++ ) {
//do stuff
}
- Need to create at least 2 variables (index,length)
- Need to check if the index is smaller than the length
- Need to increase the index
- the
for
loop has 3 parameters
- 需要创建至少 2 个变量(索引、长度)
- 需要检查索引是否小于长度
- 需要增加索引
- 所述
for
环具有3个参数
Now tell me why this should be faster than:
现在告诉我为什么这应该比:
var length = array.length;
while( --length ) { //or length--
//do stuff
}
- One variable
- No checks
- the index is decreased (Machines prefer that)
while
has only one parameter
- 一变量
- 没有检查
- 指数下降(机器更喜欢)
while
只有一个参数
I was totally confused when Chrome 28 showed that the for loop is faster than the while. This must have ben some sort of
当 Chrome 28 显示 for 循环比 while 更快时,我完全感到困惑。这一定是某种
"Uh, everyone is using the for loop, let's focus on that when developing for chrome."
“呃,每个人都在使用 for 循环,让我们在为 chrome 开发时专注于这一点。”
But now, in 2014 the while loop is back on chrome. it's 2 times faster , on other/older browsers it was always faster.
但是现在,在 2014 年,while 循环又回到了 chrome 上。它快 2 倍,在其他/旧浏览器上它总是更快。
Lately i made some new tests. Now in real world envtheitroadement those short codes are worth nothing and jsperf can't actually execute properly the while loop, because it needs to recreate the array.length which also takes time.
最近我做了一些新的测试。现在在现实世界环境中,这些短代码一文不值,jsperf 实际上无法正确执行 while 循环,因为它需要重新创建 array.length,这也需要时间。
you CAN'T get the actual speed of a while loop on jsperf.
您无法在 jsperf 上获得 while 循环的实际速度。
you need to create your own custom function and check that with window.performance.now()
您需要创建自己的自定义函数并检查 window.performance.now()
And yeah... there is no way the while loop is simply faster.
是的...... while 循环不可能更快。
The real problem is actually the dom manipulation / rendering time / drawing time or however you wanna call it.
真正的问题实际上是 dom 操作/渲染时间/绘图时间,或者你想怎么称呼它。
For example i have a canvas scene where i need to calculate the coordinates and collisions... this is done between 10-200 MicroSeconds (not milliseconds). it actually takes various milliseconds to render everything.Same as in DOM.
例如,我有一个画布场景,我需要计算坐标和碰撞......这是在 10-200 微秒(不是毫秒)之间完成的。它实际上需要不同的毫秒来渲染所有内容。与 DOM 中的相同。
BUT
但
There is another super performant way using the for loop
in some cases... for example to copy/clone an array
loop
在某些情况下,还有另一种使用 for 的超高性能方式......例如复制/克隆数组
for(
var i = array.length ;
i > 0 ;
arrayCopy[ --i ] = array[ i ] // doing stuff
);
Notice the setup of the parameters:
注意参数的设置:
- Same as in the while loop i'm using only one variable
- Need to check if the index is bigger than 0;
- As you can see this approach is different vs the normal for loop everyone uses, as i do stuff inside the 3th parameter and i also decrease directly inside the array.
- 和 while 循环一样,我只使用一个变量
- 需要检查索引是否大于0;
- 正如您所看到的,这种方法与每个人都使用的普通 for 循环不同,因为我在第 3 个参数内执行操作,并且我也直接在数组内减少。
Said that, this confirms that machines like the --
说到这里,这证实了像这样的机器——
writing that i was thinking to make it a little shorter and remove some useless stuff and wrote this one using the same style:
写我想把它缩短一点并删除一些无用的东西并使用相同的风格写这个:
for(
var i = array.length ;
i-- ;
arrayCopy[ i ] = array[ i ] // doing stuff
);
Even if it's shorter it looks like using i
one more time slows down everything.
It's 1/5 slower than the previous for
loop and the while
one.
即使它更短,看起来i
多使用一次也会减慢一切。它比前一个for
循环和上while
一个循环慢 1/5 。
Note:the ;
is very important after the for looo without {}
注:该;
是以后的looo非常重要的,而不{}
Even if i just told you that jsperf is not the best way to test scripts .. i added this 2 loops here
即使我只是告诉你 jsperf 不是测试脚本的最佳方式......我在这里添加了这 2 个循环
http://jsperf.com/caching-array-length/40
http://jsperf.com/caching-array-length/40
And here is another answer about performance in javascript
这是关于 javascript 性能的另一个答案
https://stackoverflow.com/a/21353032/2450730
https://stackoverflow.com/a/21353032/2450730
This answer is to show performant ways of writing javascript. So if you can't read that, ask and you will get an answer or read a book about javascript http://www.ecma-international.org/ecma-262/5.1/
这个答案是为了展示编写 javascript 的高效方法。因此,如果您看不懂,请询问,您会得到答案或阅读有关 javascript 的书http://www.ecma-international.org/ecma-262/5.1/
回答by przemoc
http://jsperf.com/caching-array-length/60
http://jsperf.com/caching-array-length/60
The latest revision of test, which I prepared (by reusing older one), shows one thing.
我准备的最新版本的测试(通过重用旧版本)显示了一件事。
Caching length is not that much important, but it does not harm.
缓存长度不是那么重要,但它没有坏处。
Every first run of the test linked above (on freshly opened tab) gives best results for the last 4 snippets (3rd, 5th, 7th and 10th in charts) in Chrome, Opera and Firefox in my Debian Squeeze 64-bit (my desktop hardware). Subsequent runs give quite different result.
上面链接的测试的每次第一次运行(在新打开的选项卡上)在我的 Debian Squeeze 64 位(我的桌面硬件)。随后的运行给出了完全不同的结果。
Performance-wise conclusions are simple:
性能方面的结论很简单:
- Go with for loop (forward) and test using
!==
instead of<
. - If you don't have to reuse the array later, then while loop on decremented length and destructive
shift()
-ing array is also efficient.
- 使用 for 循环(向前)并使用
!==
代替<
. - 如果您以后不必重用数组,那么在递减长度和破坏性
shift()
数组上的 while 循环也是有效的。
tl;dr
tl;博士
Nowadays (2011.10) below pattern looks to be the fastest one.
现在(2011.10)下面的模式看起来是最快的。
for (var i = 0, len = arr.length; i !== len; i++) {
...
}
Mind that caching arr.length
is not crucial here, so you can just test for i !== arr.length
and performance won't drop, but you'll get shorter code.
请注意,缓存arr.length
在这里并不重要,因此您可以进行测试i !== arr.length
并且性能不会下降,但您将获得更短的代码。
PS: I know that in snippet with shift()
its result could be used instead of accessing 0th element, but I somehow overlooked that after reusing previous revision (which had wrong while loops), and later I didn't want to lose already obtained results.
PS:我知道在代码片段中shift()
可以使用其结果而不是访问第 0 个元素,但是在重用以前的修订版(while 循环错误)之后,我不知何故忽略了这一点,后来我不想丢失已经获得的结果。
回答by valbaca
"Best" as in pure performance? or performance ANDreadability?
纯性能中的“最佳”?或性能和可读性?
Pure performance "best" is this, which uses a cache and the ++prefix operator (my data: http://jsperf.com/caching-array-length/189)
纯性能“最佳”就是这样,它使用缓存和 ++prefix 运算符(我的数据:http: //jsperf.com/caching-array-length/189)
for (var i = 0, len = myArray.length; i < len; ++i) {
// blah blah
}
I would argue that the cache-less for-loop is the best balance in execution time and programmer reading time. Every programmer that started with C/C++/Java won't waste a ms having to read through this one
我认为无缓存 for 循环是执行时间和程序员阅读时间的最佳平衡。每个从 C/C++/Java 开始的程序员都不会浪费一毫秒来阅读这个
for(var i=0; i < arr.length; i++){
// blah blah
}
回答by Shushanth Pallegar
**cache the array length inside the loop ,some seconds of time will be eluded . Depends on the items in the array if there are more items in array there is major difference with respect to Ms of time*
**在循环内缓存数组长度,将避免几秒钟的时间。取决于数组中的项目,如果数组中有更多项目,则时间女士有很大差异*
**
**
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***
**
**
回答by Sergio
This looks to be the fastest wayby far...
var el;
while (el = arr.shift()) {
el *= 2;
}
Take into account that this will consume the array, eating it, and leaving nothing left...
考虑到这将消耗阵列,吃掉它,并且什么都不留下......