2

I'm trying out two different ways of joining two arrays and using huge arrays to judge their performances but I'm getting an error on the second option and I don't understand why.

I first filled both with 10,000,000 elements with values equal to their index.

var arr1 = [];
var arr2 = [];
for (var i = 0; i < 10000000; i++) {
    arr1[i] = i;
} 
for (var i = 0; i < 10000000; i++) {
    arr2[i] = i;
}

Then:

Option 1 completes fine in ~520ms:

var newArr = arr1.concat(arr2);

Option 2 though throws the following error:

Array.prototype.push.apply(arr1, arr2);

Error:

/private/var/folders/j6/3fs5_k3n17z_0j2xrwj6sphw0000gn/T/CodeRunner/Untitled 9.js:12
Array.prototype.push.apply(arr1, arr2);
                     ^

RangeError: Maximum call stack size exceeded
    at Object.<anonymous> (/private/var/folders/j6/3fs5_k3n17z_0j2xrwj6sphw0000gn/T/CodeRunner/Untitled 9.js:12:22)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:136:18)
    at node.js:963:3

Edit

Per one of the comments, I changed Option 2 to:

setTimeout(function () {
    Array.prototype.push.apply(arr1, arr2);
}, 0);

And I'm still getting:

/private/var/folders/j6/3fs5_k3n17z_0j2xrwj6sphw0000gn/T/CodeRunner/Untitled 9.js:16
    Array.prototype.push.apply(arr1, arr2);
                         ^

RangeError: Maximum call stack size exceeded
    at null._onTimeout (/private/var/folders/j6/3fs5_k3n17z_0j2xrwj6sphw0000gn/T/CodeRunner/Untitled 9.js:16:23)
    at Timer.listOnTimeout (timers.js:92:15)
qarthandso
  • 2,100
  • 2
  • 24
  • 40
  • "RangeError: Maximum call stack size exceeded" - What's your question? – Amit May 21 '16 at 19:05
  • Stack Overflow. You went past the most things Javascript can do in a split second. Try doing ```setTimeout(function(){Array.prototype.push.apply(arr1, arr2);},0);``` and see if it helps – vtange May 21 '16 at 19:10
  • @vtange I edited the question to reflect what you said. Why am I still getting this error? And not getting it on _Option 1_? – qarthandso May 21 '16 at 19:19
  • And your question is? – Oleg V. Volkov May 21 '16 at 19:21
  • @OlegV.Volkov if I'm getting a call stack error for the second option, why am I not getting it for the first? – qarthandso May 21 '16 at 19:23
  • @qarthandso, because there's only one argument in `concat`. What `apply` does is making a second call under the hood that looks like `arr1.push(arr2[0], arr[1], arr[2], arr[3], arr[4], arr[5], ..., arr2[1000000000])`. Most engines can't deal with 10000000 separate arguments. – Oleg V. Volkov May 23 '16 at 01:07
  • Related: http://stackoverflow.com/q/11193421/936986. It also have some empirically calculated limits for browser versions that were current back then. – Oleg V. Volkov May 25 '16 at 14:52

1 Answers1

4

The apply() method unrolls provided array to arguments list. ECMAScript specification itself have no limits on amount of arguments for function, but most JS engines have implementation-specifc limits because they use fixed or limited size structure for each function call on their internal stack for performance purposes. Though this limit is generally pretty high, it is certainly well below 10000000 arguments and that's why you get error "Maximum call stack size exceeded".

Oleg V. Volkov
  • 21,719
  • 4
  • 44
  • 68