for loop vs forEach performance in javascript and credibility of jsperf results
Asked Answered
Y

3

11

I don't trust results from jsperf measuring performance of for loop vs forEach. At least for chrome and firefox on my machine results are completely different than the ones being advertised in jsperf.
http://jsperf.com/foreach-vs-loop (mine)
http://jsben.ch/#/BQhED (more popular)
On my laptop running Ubuntu 11.10 I have the following results in Firefox:

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

Unfortunately, Chrome doesn't return the result of console.timeEnd() but the running times are same and just faster in Chrome. I'm observing that forEach almost 10x faster than for loop in Chrome, and 3x faster in Firefox.
In Chrome I'm getting approximately these running times:

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

Here's the code I ran in Firefox and Chrome console.

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});

Running the tests for one million items has the same performance difference. Could you please advise if I'm missing something and I should trust jsperf results instead of the real ones I'm observing? Of course I do trust the real results that I can see right here right now in my browser.

EDIT: The test scenario isn't objective as discovered during discussion with @Blender. Looks like js optimizer optimezes forEach loop with no action in it and thus obscures running time if there were some real code.

Yet answered 17/3, 2012 at 1:54 Comment(18)
jsPerf does real tests. The testing framework that it uses is just a more complex version of yours. Also, make sure to account for different browsers' JS engines.Husted
Not a javascript developer, but I would guess the interpreter is optimizing v; to nothing, but still looks up the value of arr[j].Floodgate
The point of jsperf is to demonstrate relative performance differences. You are still seeing the same relative performance. What exactly are you doubting?Hart
@blender so what kind of the real tests are they if they don't prove in real scenario?Yet
@Floodgate removed arr[i] and v from both and get slightly better performance of for loop but still forEach is much faster.Yet
@Hart yes but this relative performance is absolutely different and I'm observing forEach loop is perfoming much faster as opposite to jsperf results and common belief that for loop is faster.Yet
@spyboost: What kind of real scenario involves looping 100,000 times? Also, Chrome's V8 JS engine optimizes differently than Mozilla's SpiderMonkey engine, which probably is why you're seeing different results in different browsers.Husted
Which is faster absolutely depends on the browser. Native forEach can be optimized very differently, if the browser supports it. And the numbers you quote in your question show the same tendency. I really don't know what exactly your question is.Hart
@blender I'm not arguing that I'm seeing different performance characteristics in different browsers. I'm arguing that forEach loop performs much faster opposing to common belief that for loop is faster. And this test proves it for BOTH browsers. Number of times doesn't matter, it can be 100K or million and still it'll be faster. I'm concerned that same test runs with different results in jsperf leading to conclusion that forEach is way too slow compared to for loop.Yet
I'm not sure where you are getting those numbers. On my machine, I get 6ms and 83ms for the for and forEach loops, respectively (using your code).Husted
@Hart I agree that native forEach is (and should be optimized). My question is why jsperf shows absolutely different results where forEach is 2x slower? Also this is related to the "Busted Myth" docs.google.com/present/… where they try to prove that native forEach is MUCH SLOWER as opposite to what I'm seeing. Why they claim it's SLOWER when I see it's MUCH FASTER?Yet
@Husted that's weird. Looks like it really depends on the js optimizer/compiler/whatever. But I also conducted the same test on another windows machine and it just proved again forEach being same order faster.Yet
I ran your code on a Linux machine (3.2.9, 64-bit) on Google Chrome 19.Husted
I don't see where you see that. The numbers you quote in your question shows that forEach is faster every time. The chart at the bottom of the "more popular" test shows that forEach is faster most of the time, but that it widely differs among different browsers. Your statements and (implicit) question is very confusing.Hart
@Hart which chart you are talking about? jsperf charts show that most of the time for loop is faster.Yet
@spyboost: I modified your code to be more fair. Can you take a look at it? jsfiddle.net/ssSt5/2Husted
@Husted ok. I got it. Thanks for looking into it. Optimizer in forEach probably obscured real running time results which take place with function invocation.Yet
@Husted is there a way to accept your last comment as the answer? My "test" wasn't objective.Yet
H
10

I modified your code to be more fair. Can you take a look at it?

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);
});

Your test wasn't 100% raw number crunching, so the benchmark was being optimized unfairly by some browsers.

Husted answered 17/3, 2012 at 2:40 Comment(3)
In your fiddle, for loop seems to be faster. But when I run the same code in the developer console, forEach wins everytime. Why would that be happening?Martinemartineau
@KushagraGour: No clue. Ask a question.Husted
Hey 2012, 2018 here: Both are similar now.Tycho
U
5

Here is a real test: http://jsfiddle.net/ssSt5/57/ (run it multiple times)

Apparently they are practically the same.

So when there is real computation going on, for vs forEach doesn't matter. Other factors are much bigger influence on performance. Specially after the run time has applied optimizations.

Uriel answered 20/5, 2016 at 7:30 Comment(0)
C
-1

This site shows results for a full range of JavaScript looping approaches http://www.jsbenchmarks.com/?anywhichway/loop/master/benchmark.js. The results are the average of all site visitors running the benchmark compared to your own if you choose to run the benchmark.

Copulation answered 5/1, 2017 at 16:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.