Dangers of JS Spread Operator
The spread operator can be used to (among other things) expand arrays in places where elements are expected.
Example:
const data = [0, 1, 2];
const additionalData = [3, 4, 5];
data.push(...additionalData);
That's handy but if you aren't careful you can run into: RangeError: Maximum call stack size exceeded at Array.push
This happens if the array you're spreading is too large.
Let's imagine this scenario:
const allData = [];
for (const month of months) {
const dataForMonth = await fetchDataForMonth(month);
allData.push(...dataForMonth);
}
If we don't know how many elements dataForMonth might have we could hit this limit. In this case, instead of arr.push(...data)
we can do arr.push.apply(arr, data)
.
To test, I ran this script on the node repl in my terminal:
let arrOne = [];
const arrTwo = [];
while (true) {
arrTwo.push(null);
console.log('items: ', arrTwo.length);
arrOne.push(...arrTwo);
arrOne = [];
}
and the last log before the error is: items: 125639
Interestingly, I tried a couple of variations and got different results, suggesting this isn't a general limitation of the spread operator but depends in the context it's being used:
- First Variation:
const arrOne = [];
const arrTwo = [];
while (true) {
arrTwo.push(null);
console.log('items: ', arrTwo.length);
const combined = [...arrOne, ...arrTwo];
}
I kept this running for a while but eventually stopped it before it errored as it had got my laptop fans running loudly. I presume it would have errored eventually but can't say for certain. It got to items: 225035
before I stopped the script with no error.
- Second Variation:
const arr = [];
const func = () => null;
while (true) {
arr.push(null);
console.log('item count: ', arr.length);
func(...arr);
}
This hit the RangeError
with the item count: 120587
as the final line of logging.