在JavaScript中,for循环和forEach循环的性能以及jsperf结果的可信度问题

11

我不太相信 jsperf 上测试 for 循环和 forEach 方法的性能结果,至少在我的机器上,对于 Chrome 和 Firefox 来说,结果与 jsperf 上所宣传的完全不同。以下是我在 Ubuntu 11.10 上运行 Firefox 的测试结果:
http://jsperf.com/foreach-vs-loop (我自己的测试)
http://jsben.ch/#/BQhED(更受欢迎的测试)

for: total=1641 ms, avg=164.1 ms  
forEach: total=339 ms, avg=33.9 ms  

uname -a:  
Linux 3.0.0-16-generic #29-Ubuntu SMP Tue Feb 14 12:48:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

很不幸,Chrome 不会返回 console.timeEnd() 的结果,但是它的运行时间与其他浏览器一样,只是比其他浏览器更快。我观察到在 Chrome 中,forEach 比 for 循环要快大约 10 倍,在 Firefox 中快约 3 倍。
在 Chrome 中,我得到了大约这些运行时间:

for: avg=80 ms
forEach: avg=6 ms

这是我在Firefox和Chrome控制台运行的代码。

var arr = [];
for(var i = 0; i < 100000; i++) arr[i]=i;

var numberOfRuns = 10;

function time(name, f){
    console.time(name);
    f();
    return console.timeEnd(name);
}

function runTest(name, f){
    var totalTime = 0;
    for(var r = 0; r < numberOfRuns; r++)
        totalTime += time(name,f);
    return totalTime;
}

var forTime = runTest('for', function(){
    for(var j = 0; j < arr.length; j++)
        arr[j];    
});
var forEachTime = runTest('forEach', function(){
    arr.forEach(function(v){v;});
});

console.log('for', {total:forTime, avg:forTime / numberOfRuns});
console.log('forEach', {total:forEachTime, avg:forEachTime / numberOfRuns});

测试一百万个项目的运行速度差异相同。请问我是否遗漏了什么,我应该相信jsperf的结果而不是我在浏览器里看到的真实结果吗?当然,我确实相信我在这里和现在可以看到的真实结果。

编辑:通过与@Blender的讨论发现,测试场景并不客观。看起来js优化器会优化没有任何操作的forEach循环,因此如果有一些真正的代码,则会掩盖运行时间。


2
jsPerf进行真实的测试。它使用的测试框架只是您的版本的更复杂的版本。此外,一定要考虑不同浏览器的JS引擎。 - Blender
我不是JavaScript开发人员,但我猜解释器正在将v;优化为空,但仍然查找arr[j]的值。 - ta.speot.is
@deceze 是的,但是这种相对性能绝对不同,我观察到forEach循环比jsperf结果和普遍认为的for循环更快。 - Diamond Hands
哪个更快绝对取决于浏览器。如果浏览器支持,本地的forEach可以被优化得非常不同。你在问题中引用的数字也显示了相同的趋势。我真的不知道你的问题是什么。 - deceze
我不确定你从哪里得到那些数字。在我的机器上,使用你的代码,我得到了for循环和forEach循环分别为6毫秒83毫秒的结果。 - Blender
显示剩余13条评论
3个回答

10

我修改了你的代码,使其更加公平。你能看一下吗?

var arr = [];
for (var i = 0; i < 100000; i++) arr[i] = i;

var numberOfRuns = 100;

function runTest(name, f) {
    var totalTime = 0;
    console.time(name);

    for (var r = 0; r < numberOfRuns; r++) {
        f();
    }

    return console.timeEnd(name);
}

function testFunction(v) {
    v;
}

var forTime = runTest('for', function() {
    for (var j = 0; j < arr.length; j++) {
        testFunction(arr[j]);
    }
});

var forEachTime = runTest('forEach', function() {
    arr.forEach(testFunction);
});

你的测试并非100%的原始数字计算,因此一些浏览器正在通过不公平的优化来优化基准。


5
在您的小提琴(代码示例)中,for循环似乎更快。但是,当我在开发者控制台中运行相同的代码时,forEach每次都赢得胜利。为什么会发生这种情况? - Kushagra Gour
1
@KushagraGour:没有头绪。提出一个问题吧。 - Blender
嘿,2012年,这里是2018年:现在两者很相似。 - Seraf

5

这是一个真实的测试:http://jsfiddle.net/ssSt5/57/(多次运行它)

显然它们几乎是相同的。

因此,在进行实际计算时,for vs forEach并不重要。其他因素对性能的影响更大。尤其是在运行时应用了优化之后。


-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接