简体   繁体   English

array.forEach比本机迭代运行得更快? 怎么样?

[英]array.forEach running faster than native iteration? How?

http://jsperf.com/testing-foreach-vs-for-loop http://jsperf.com/testing-foreach-vs-for-loop

It was my understanding that Test Case 2 should run more slowly than Test Case 1 -- I wanted to see how much more slowly. 我的理解是,测试案例2的运行速度应该比测试案例1慢 - 我想看看速度有多慢。 Imagine my surprise when I see it runs more quickly! 当我看到它运行得更快时,想象一下我的惊喜!

What's going on here? 这里发生了什么? Behind the scenes optimizaiton? 在幕后优化? Or is .forEach cleaner AND faster? 或者.forEach更清洁,更快?

Testing in Chrome 18.0.1025.142 32-bit on Windows Server 2008 R2 / 7 64-bit 在Windows Server 2008 R2 / 7 64位上以32位Chrome 1.5.0.1025.142进行测试

There are many iteration optimizations that your for loop is missing such as: 您的for循环缺少许多迭代优化,例如:

  • cache the array length 缓存数组长度
  • iterate backwards 向后迭代
  • use ++counter instead of counter++ 使用++计数器而不是计数器++

These are the ones that I have heard of and used, I am sure there are more. 这些是我听过和使用的,我相信还有更多。 If memory serves me correct, the backwards iterating while loop is the fastest of all looping structures (in most browsers). 如果内存对我来说是正确的,则向后迭代while循环是所有循环结构中最快的(在大多数浏览器中)。

See this jsperf for some examples. 有关示例,请参阅此jsperf

Edit: links for postfix vs prefix perf test and iterating backwards . 编辑: 后缀与前缀perf测试的链接并向后迭代 I was not able to find my reference for using +=1 instead of ++, so I have removed it from the list. 我无法找到使用+ = 1而不是++的参考,所以我已将其从列表中删除。

UPDATE: 更新:

A lot of the old tricks in these answers are great for interpreted JS in older browsers. 这些答案中的许多旧技巧对于旧版浏览器中的解释JS非常有用。

In any modern JS implementation including all modern browsers, Node, and the latest mobile webviews, inline functions can actually be cached by the JIT (JS compiler), making forEach a much faster option for array iteration, typically. 在包括所有现代浏览器,Node和最新移动webview的任何现代JS实现中,内联函数实际上可以由JIT(JS编译器)缓存,通常使得forEach更快速地进行数组迭代。 It used to be the opposite where just making calls to a function repeatedly required a build-up/teardown process that could severely diminish performance of a non-trivial loop. 它曾经是相反的,只是反复调用函数需要一个可能严重降低非平凡循环性能的构建/拆除过程。

For best performance I'd avoid referencing anything that wasn't passed as an argument or defined inside the function itself if you don't have to. 为了获得最佳性能,我将避免引用任何未作为参数传递或在函数内部定义的内容(如果您不需要)。 I'm not 100% sure that matters but I could see why it might. 我不是百分百肯定这很重要,但我可以理解为什么会这样。

Getter values that involve any kind of lookup process like array lengths or DOM node properties are probably also still best cached to a variable. 涉及任何类型的查找过程(如数组长度或DOM节点属性)的Getter值可能仍然最好缓存到变量。

But beyond that I'd try to just let the basic principle of work avoidance guide your perf efforts. 但除此之外,我试着让避免工作的基本原则指导你的工作。 Pre-calculating things that don't need to be recalculated in a loop, or caching a query selector result to var rather than rummaging in the DOM repeatedly are good examples of this. 预先计算不需要在循环中重新计算的事物,或者将查询选择器结果缓存到var而不是在DOM中反复搜索这些都是很好的例子。 Trying too hard to take advantage of JIT behavior is probably going to get pretty arcane and not likely to hold up over time or across all JITs. 尝试过于努力以利用JIT行为可能会变得非常神秘,并且不太可能随着时间推移或跨越所有JIT。

OLD ANSWER: 老答案:

Okay, forget wall of text. 好吧,忘了文字墙。 Bullet points: 要点:

var i = someArray.length; //length is cached
someArray.reverse(); //include this only if iterating in 0-(length-1) order is important

while(i--){
//run a test statement on someArray[i];
}
  • length is cached and immediately made into the index 长度被缓存并立即进入索引

  • The benefit of iterating backwards in JS AFAIK is avoiding a logical operator with two operands. 在JS AFAIK中向后迭代的好处是避免使用具有两个操作数的逻辑运算符。 In this case we're just evaluating a number. 在这种情况下,我们只是评估一个数字。 It's true or it's zero and false. 这是真的,或者是零和假。

  • I also find it elegant. 我也觉得它很优雅。

Reading length from array at each iteration may be slow, but forEach is comomonly slower, cause function call isn't cheap operation in js. 在每次迭代时从array中读取length可能很慢,但是对于每个都是较慢的,因为函数调用在js中不是廉价的操作。

PS: forEach is 14% slower on FF10. PS: forEach在FF10上慢了14%。

They're approximately the same for me in Opera. 在Opera中,它们对我来说大致相同。 Something to note is that your conditional in the for() is array.length. 需要注意的是,for()中的条件是array.length。 If you cache the length of the array in a variable, and then loop, you should see better performance. 如果在变量中缓存数组的长度,然后循环,则应该看到更好的性能。

Maybe the for() is slower because the loop applies 'array.length' to each iteration, to get the array's length. 也许for()更慢,因为循环将'array.length'应用于每次迭代,以获得数组的长度。

Try: 尝试:

var nri = array.length;
for( var i = 0; i < nri; i++ ){
   // ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM