29

can anyone tell me whats the reason that array.forEach is slower than for loop in javascript. Is there any particular reason.

Here's the code that I was trying to find the performance.

// Populate the base array
    var arr = [];
    for (var i = 0; i < 1000; i++) {
      arr[i] = i;
    }

    function someFn(i) {
      return i * 3 * 8;
    }

Using Array.forEach :

arr.forEach(function (item){
  someFn(item);
})

Using for loop :

for (var i = 0, len = arr.length; i < len; i++) {
  someFn(arr[i]);
}

I tested it on test runner . Here are the results: enter image description here

As you can see Array.ForEach is 96% slower than for loop. Thanks in advance.

Prateek Gupta
  • 1,129
  • 1
  • 11
  • 24
  • This may help http://stackoverflow.com/questions/43031988/for-vs-foreach-javascript-efficiency/43032526#43032526 – LF00 May 06 '17 at 14:48
  • 1
    It's probably because `forEach` requires a function call for each element. That doesn't quite explain why it's 96% faster though, you'd expect 50% since you make 1 function call instead of 2 for each element. It's possible the engine is able to optimize the `someFn` function which means it doesn't need to make a function call. Perhaps you can modify your performance test to check this. – Halcyon May 06 '17 at 14:53
  • This is also good, http://stackoverflow.com/questions/22155280/why-is-native-javascript-array-foreach-method-significantly-slower-than-the-stan – parlad May 06 '17 at 14:53
  • 1
    Even if `forEach` is slower, unlike the JSPerf (which i don't trust) results, it's only slightly slower... Yet sometimes it can turn out to be significantly faster than the `for` loop. Check [this](http://jsben.ch/#/fxaYy) out. – Redu May 06 '17 at 21:33
  • https://youtu.be/EhpmNyR2Za0?t=17m15s – Bergi Apr 06 '18 at 14:39
  • 2 function calls.... It's took me till now to realise `arr.forEach(function(item) { someFn(item); })` can be written as `arr.forEach (someFn)` - more concise and cuts out the anonymous function – mgraham Sep 27 '19 at 12:33
  • Can you let me know what tool did you use to measure the difference, please? I would be very thankful – Zeyad Shaban Dec 27 '20 at 14:31

1 Answers1

32

Updated based on feedback from @BenAston & @trincot

Roughly, this is what's happening in both cases:

For loop

  1. Set the index variable to its initial value
  2. Check whether or not to exit the loop
  3. Run the body of your loop
  4. Increment the index variable
  5. Back to step 2

The only overhead that happens on every iteration is the check & the increment, which are very low-load operations.

forEach loop

  1. Instantiate the callback function
  2. Check if there's a next element to process
  3. Call the callback for the next element to process, with a new execution context (this comprises the "scope" of the function; so its context, arguments, inner variables, and references to any outer variables -- if used)
  4. Run the contents of your callback
  5. Teardown of callback function call
  6. Return to step 2

The overhead of the function setup & teardown in steps 3 & 5 here are much greater than that of incrementing & checking an integer for the vanilla for-loop.

That said, many modern browsers recognize & optimize forEach calls, and in some cases, the forEach might even be faster!

Community
  • 1
  • 1
tavnab
  • 2,594
  • 1
  • 19
  • 26
  • 'Closure' and 'teardown' seem unfamiliar to me, could you elaborate on that please? – Aanchal1103 May 06 '17 at 15:09
  • 2
    A closure (answer updated with link) is what gives you access to the variables of an outer function (i.e. whatever's calling the `forEach`, or wherever you've declared your callback if not inline) from an inner function (your callback). It takes some CPU cycles & memory to set that up for each call. By teardown, I just meant the additional work that the JavaScript engine has to do to clean up after itself following any function call. All function calls have some overhead at the start and at the end that, if not optimized out by e.g. function inlining, will impact performance. – tavnab May 06 '17 at 15:18
  • Great! Thanks :) Upvoted! – Aanchal1103 May 06 '17 at 15:21
  • 2
    The creation of a closure is not linked to `forEach` itself as one might pass a simple arrow function like `x => y += x`, which has no closure. – trincot May 06 '17 at 15:27
  • @trincot you're right; a closure is not created every time (hence my sneaking in of the word "often" in my answer a few minutes ago :) ), and isn't a specific to the `forEach` use-case, but I think it's a common enough source of overhead for most practical cases to be mentioned here. – tavnab May 06 '17 at 15:42
  • @trincot I updated my answer to make it clearer that closures are not always needed/created. Thanks! – tavnab May 06 '17 at 15:49
  • Closure is IMO the wrong term here. You mean function-object instantiation and execution context creation. – Ben Aston May 06 '17 at 17:18
  • A closure is a reference to an outer LexicalEnvironment. It is the copying of a reference when the initial function object is instantiated (which will happen once), and this is then copied again with each invocation of the callback when the associated execution context is created. – Ben Aston May 06 '17 at 17:21
  • @BenAston very true; I can see how my use of "closure" isn't clear here. I'll update accordingly. thanks! – tavnab May 06 '17 at 17:22
  • @trincot Fat arrow functions do create closures. But the expense of doing so (see my above) is marginal. – Ben Aston May 06 '17 at 17:24
  • 1
    this is a fair and interesting question. Yes, creating the callback inline probably affected the results (because the filtering function would be re-created on each re-run of the forEach in the timing loop). But `[].forEach` is also an order of magnitude slower than its obvious implementation, which runs as fast or faster than the for loop: `function forEach(a, fn) { for (var i=0; i – Andras May 08 '17 at 22:49
  • I've also found a custom implementation runs much quicker: function each(arr,cb){ for(var i=0;i – Patrick Sturm Aug 25 '18 at 20:50