Подтвердить что ты не робот

"RangeError: превышен максимальный размер стека вызовов". Почему?

Если я запустил

Array.apply(null, new Array(1000000)).map(Math.random);

на Chrome 33, я получаю

RangeError: Maximum call stack size exceeded

Почему?

4b9b3361

Ответ 1

Браузеры не могут обрабатывать множество аргументов. См. Этот пример, например:

alert.apply(window, new Array(1000000000));

Это дает RangeError: Maximum call stack size exceeded, который совпадает с вашей проблемой.

Чтобы решить эту проблему, выполните:

var arr = [];
for(var i = 0; i < 1000000; i++){
    arr.push(Math.random());
}

Ответ 2

Здесь он терпит неудачу при Array.apply(null, new Array(1000000)), а не в вызове .map.

Все аргументы функций должны вписываться в callstack (по крайней мере, указатели на каждый аргумент), поэтому в них слишком много аргументов для вызова.

Вам нужно понять, что такое стек вызовов.

Stack - это структура данных LIFO, которая похожа на массив, который поддерживает только push и pop методы.

Позвольте мне объяснить, как это работает на простом примере:

function a(var1, var2) {
    var3 = 3;
    b(5, 6);
    c(var1, var2);
}
function b(var5, var6) {
    c(7, 8);
}
function c(var7, var8) {
}

Когда вызывается функция a, она вызывается b и c. Когда вызываются b и c, локальные переменные a недоступны там из-за роли определения роли Javascript, но механизм Javascript должен помнить локальные переменные и аргументы, поэтому он будет вставлять их в столбец вызова. Скажем, вы используете механизм JavaScript с языком JavaScript, например Narcissus.

Мы реализуем массив callStack как:

var callStack = [];

Каждый раз, когда вы вызываете функцию, мы вставляем локальные переменные в стек:

callStack.push(currentLocalVaraibles);

Как только вызов функции завершен (как в a, мы вызвали b, b завершено, и мы должны вернуться к a), мы возвращаем локальные переменные, вставляя стек:

currentLocalVaraibles = callStack.pop();

Итак, когда в a мы снова вызываем c, нажимаем локальные переменные в стеке. Теперь, как вы знаете, компиляторы, чтобы быть эффективными, определяют некоторые ограничения. Здесь, когда вы делаете Array.apply(null, new Array(1000000)), ваш объект currentLocalVariables будет огромным, поскольку внутри него будут переменные 1000000. Поскольку .apply будет передавать каждый из данного элемента массива в качестве аргумента функции. После того, как он будет перенесен в стек вызовов, это превысит ограничение на количество стека вызовов, и оно выведет эту ошибку.

Такая же ошибка происходит при бесконечной рекурсии (function a() { a() }) как слишком много раз, материал был перенесен в стек вызовов.

Обратите внимание, что я не инженер-компилятор, и это просто упрощенное представление о том, что происходит. Это действительно сложнее, чем это. Обычно то, что вызывается в callstack, называется фрейм стека, в котором содержатся аргументы, локальные переменные и адрес функции.

Ответ 3

Ответ с for верен, но если вы действительно хотите использовать функциональный стиль, избегающий инструкции for, вы можете использовать следующее вместо своего выражения:

Array.from(Array (1000000),() = > Math.random());

Метод Array.from() создает новый экземпляр массива из объекта, подобного массиву или итерации. Второй аргумент этого метода - это функция отображения для каждого элемента массива.

Следуя той же идее, вы можете переписать ее с помощью ES2015 Spread operator:

[... Array (1000000)]. map (() = > Math.random())

В обоих примерах вы можете получить индекс итерации, если вам нужно, например:

[... Array (1000000)]. map ((, i) = > я + Math.random())