Array.prototype.pushArray to fix "Maximum call stack size exceeded" in Array.prototype.push

in the wild, there exists this pattern to push elements from a source array to a destination array

destinationArray.push(...sourceArray) // ... = spread operator

this pattern is used cos its fast, faster than dst = dst.concat(src) or dst = [...dst, ...src]
and cos its short, shorter than for (let i = 0; i < src.length; i++) dst.push(src[i])

problem

the source array is limited by the Maximum call stack size of around 100K in nodejs and 500K in firefox

// problem
[].push(...Array.from({ length: 1000*1000 }))
// Uncaught RangeError: Maximum call stack size exceeded

solution

destinationArray.pushArray(sourceArray)

pushArray, aka: array concat in place, aka: mutable array concat

// array.pushArray polyfill in typescript
(Array.prototype as any).pushArray = function pushArray(...otherList: any[]) {
  let c = 0; // count pushed elements
  for (let a = 0; a < otherList.length; a++) {
    const other = otherList[a];
    for (let i = 0; i < other.length; i++) {
      this.push(other[i]);
      c++;
    }
  }
  return c;
};

(someArray as any).pushArray(otherArray1, otherArray2, [otherItem])

alternatives

using a library, like

import { pushArray } from 'push-array'
pushArray(destinationArray, sourceArray)

but imho this should be a core feature

cost

Array.prototype would become more complex, only to solve a rare edge case

related

sample use case + code transformer
[fix] Maximum call stack size exceeded (#4694) by milahu ยท Pull Request #6716 ยท sveltejs/svelte ยท GitHub
the code transformer could be implemented in eslint

1 Like

See also Array method to append another array in-place

2 Likes

aah, sorry for the duplicate

a simple benchmark suggests that concat is faster than push, which would make this proposal obsolete, assuming that a native pushArray or pushAll would not be faster than concat

That is often not the case. For example when what you already have is much longer than what you're appending. Or if you run it in Firefox (for me all of your pushX examples are 2x as fast as concat).

But more importantly, concat is a different operation. If you need to append to the destination array, rather than just build a new one, your only option is pushing one by one (or in chunks that you can spread).

2 Likes