当递归函数在 javascript 中可数时,最大调用堆栈大小超过 RangeError
Maximum call stack size exceeded RangeError when recursive function is countable in javascript
我创建了一个脚本来将数字除以选定的小数位数。一切正常,除非我设置了大量的小数位。通过 Node.js 的文件 运行 在小数数组长度达到 ~2400 时放弃,Chrome 在~1900 时放弃。
我简化了我的代码,下面的脚本示例在 ~20000
十进制数数组长度上抛出 Maximum call stack size exceeded
RangeError。我认为当循环或递归函数被无休止地调用时会抛出这个错误,但在我的例子中有可数的迭代次数。它可能是一个巨大的数字,但我的模块旨在对大数字进行数学运算。
为什么会发生这种情况,我可以避免这种 RangeError 发生吗?
var decimals = [];
var max = 20000;
recurse();
function recurse() {
decimals.push(Math.floor(Math.random()*10));
if(decimals.length === max) return;
recurse();
}
不,您可以在调用堆栈上放置多少函数调用是有限制的,因此即使您的递归函数具有可到达的基本情况,如果递归调用的数量太多,它仍然会抛出错误大.
一种解决方法是使用称为 trampoline
的技术,您不直接在函数内部执行递归调用,而是插入 return 一个新函数,然后循环执行直到达到基本情况。
使用这种技术,您的函数可以执行任意数量的递归调用,因为您不会同时将更多的函数调用放入调用堆栈,因此它不会溢出。
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));
只需使用常规循环,或类似的东西:
const random = length => Array.from({ length }, () => Math.floor(Math.random() * 10));
const decimals = random(20000);
关于调用栈:见this web page
如果你想要的是 20,000(伪随机)小数,你也可以使用类似的东西:
var maxDecimals = 20000;
var decimals = Array.from({length: maxDecimals})
.map(v => Math.floor(Math.random()*10));
console.log(decimals);
我创建了一个脚本来将数字除以选定的小数位数。一切正常,除非我设置了大量的小数位。通过 Node.js 的文件 运行 在小数数组长度达到 ~2400 时放弃,Chrome 在~1900 时放弃。
我简化了我的代码,下面的脚本示例在 ~20000
十进制数数组长度上抛出 Maximum call stack size exceeded
RangeError。我认为当循环或递归函数被无休止地调用时会抛出这个错误,但在我的例子中有可数的迭代次数。它可能是一个巨大的数字,但我的模块旨在对大数字进行数学运算。
为什么会发生这种情况,我可以避免这种 RangeError 发生吗?
var decimals = [];
var max = 20000;
recurse();
function recurse() {
decimals.push(Math.floor(Math.random()*10));
if(decimals.length === max) return;
recurse();
}
不,您可以在调用堆栈上放置多少函数调用是有限制的,因此即使您的递归函数具有可到达的基本情况,如果递归调用的数量太多,它仍然会抛出错误大.
一种解决方法是使用称为 trampoline
的技术,您不直接在函数内部执行递归调用,而是插入 return 一个新函数,然后循环执行直到达到基本情况。
使用这种技术,您的函数可以执行任意数量的递归调用,因为您不会同时将更多的函数调用放入调用堆栈,因此它不会溢出。
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));
只需使用常规循环,或类似的东西:
const random = length => Array.from({ length }, () => Math.floor(Math.random() * 10));
const decimals = random(20000);
关于调用栈:见this web page
如果你想要的是 20,000(伪随机)小数,你也可以使用类似的东西:
var maxDecimals = 20000;
var decimals = Array.from({length: maxDecimals})
.map(v => Math.floor(Math.random()*10));
console.log(decimals);