20

While reading the source code for the Quintus game engine, I found that they were making heavy use of for loops as opposed to the native forEach.

My original thought was that the native forEach method would be slightly faster than standard for loops. However, after testing my theory with these benchmarks, the for loop structures appears to be significantly faster.

After poking around, I can't seem to find out what's going on under the hood. Does anyone know the reason for the huge difference?

EDIT: To be clear, I am asking "why" is this this case. I'm not asking "which is faster".

Just a guy
  • 5,812
  • 4
  • 21
  • 25
  • 7
    A function call involves a non-trivial overhead, and `.forEach` makes a lot of function calls. – Pointy Mar 03 '14 at 19:15
  • I added a new revision which may be worth exploring: var foo = ""; var fn = function(x) { foo += x; }; for(x = 0; x < length; x++) { fn(x); } – 000 Mar 03 '14 at 19:21
  • @Pointy That's odd. I would have thought the engine would have inlined those functions as seen here: http://jsperf.com/canvas-pixelwise-manipulation-performance. Could there be something here preventing inlining? – Just a guy Mar 03 '14 at 19:22
  • @GeorgeJempty, I'd say that's a different question. That one asks "if" there is a performance difference. This question accepts that one exists and asks "why". – Just a guy Mar 03 '14 at 19:34
  • Point taken, but the why seems obvious and trivial to me. – Dexygen Mar 03 '14 at 19:36
  • You may look into some comparisons done: http://jsperf.com/for-vs-foreach/37 http://www.symphonious.net/2010/10/09/javascript-performance-for-vs-foreach/ – kheya Mar 03 '14 at 19:37
  • @DavidGranado the runtime would have to understand the `.forEach()` call as a whole, and effectively transform the whole thing into a `for` loop. That's clearly not done currently, probably because it's an awkward special case. – Pointy Mar 03 '14 at 19:43
  • @GeorgeJempty then your thoughts would be greatly appreciated. – Just a guy Mar 03 '14 at 19:58
  • 1
    @Pointy, ah...you're right. I think I've got it now. Inlining is a runtime modification to the javascript code itself. Since forEach is native, it's not happening on the same level for it to inline. – Just a guy Mar 03 '14 at 20:01
  • 2
    The duplicate marking makes little sense. The linked question asks _which_ is faster, this question ask _why_. – Etheryte Sep 10 '15 at 16:43

2 Answers2

22

The forEach includes many checks internally and isn't as straight forward as a simple loop.
See the Mozilla Javascript reference for the details:

if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisArg */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        fun.call(thisArg, t[i], i, t);
    }
  };
}
Etheryte
  • 24,589
  • 11
  • 71
  • 116
  • 2
    Good point. However, since this is all native, I'd expect the affect to be much less than the 20+ fold difference in performance. I'm thinking it might be some combination of this and something about this preventing function inlining. I'll dig in some more with these new perspectives. – Just a guy Mar 03 '14 at 19:32
  • 5
    @DavidGranado any update on this for 2017 would be appreciated – Max Heiber Dec 18 '16 at 16:00
0

thanks for pasting the implementation; there's the answer right there: fun.call is slower than fun, and the i in t test is expensive.

Seems to have tried so hard to address uncommon cases that the final result is too expensive for common use.

Andras
  • 2,995
  • 11
  • 17
  • 2
    The code posted by @Nit is not the actual implementation of the *native* `forEach` method – Bergi May 08 '17 at 23:27