Максимальный размер стека вызовов превышен RangeError, когда рекурсивная функция исчисляется в JavaScript - PullRequest
0 голосов
/ 05 июня 2018

Я создал скрипт для деления чисел на выбранное количество знаков после запятой.Все работает нормально, если я не установил огромное количество десятичных знаков.Файл, запускаемый через Node.js, сдается, когда длина массива десятичных чисел достигает ~ 2400, Chrome сдает ~ 1900.

Я упростил свой код, и приведенный ниже пример скрипта выдает Maximum call stack size exceeded RangeError на ~20000 длину массива десятичных чисел.Я думал, что эта ошибка генерируется, когда цикл или рекурсивная функция вызывается бесконечно, но в моем случае существует счетное количество итераций.Это может быть огромное количество, но мой модуль предназначен для выполнения математических операций над большими числами.

Почему это происходит и можно ли избежать этой ошибки RangeError?

var decimals = [];
var max = 20000;

recurse();

function recurse() {
  decimals.push(Math.floor(Math.random()*10));
  if(decimals.length === max) return;
  recurse();
}

Ответы [ 3 ]

0 голосов
/ 05 июня 2018

Просто используйте обычный цикл или что-то вроде:

 const random = length => Array.from({ length }, () => Math.floor(Math.random() * 10));

const decimals = random(20000);
0 голосов
/ 05 июня 2018

Относительно стека вызовов: см. эту веб-страницу

Если вы хотите получить 20 000 (псевдослучайных) десятичных знаков, вы также можете использовать что-то вроде:

var maxDecimals = 20000;
var decimals = Array.from({length: maxDecimals})
  .map(v => Math.floor(Math.random()*10));
  
console.log(decimals);
0 голосов
/ 05 июня 2018

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

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

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

var decimals = [];
var max = 20000;

function _recurse(){
  decimals.push(Math.floor(Math.random()*10));
  if(decimals.length === max) return;
  return () => _recurse();
}

const trampoline = fn => (...args) => {
  let res = fn(...args);
  while (typeof res === 'function') { res = res(); }
  return res;
}

const recurse = trampoline(_recurse);

recurse()

console.log(decimals);

Обратите внимание, что ваша проблема может быть решена без использования рекурсии гораздо более простым способом с использованием циклов.Например:

function createRandomSequence(amount) {
  const decimals = [];
  for (let i = 0; i < amount; i++) {
    decimals.push(Math.floor(Math.random()*10));
  }
  return decimals;
}

console.log(createRandomSequence(10));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...