JavaScript递归:超过了最大调用堆栈大小
JavaScript recursion: Maximum call stack size exceeded
我有一个递归函数,用于在画布上移动一些圆。覆盖的圆被放大(放大),所有其他圆被推开。推送的圆推送其他圆,依此类推,直到缩放完成。
我收到一个错误"超过了最大调用堆栈大小",我理解这个问题,但我不知道如何解决。。。我发现了三种可能的解决递归问题的方法:
- 将递归改为迭代
- 使用记忆
- 使用SetTimeout
但我认为我不能使用它们:
- 由于需要的操作数量未知,我无法实现迭代
- 我对记忆理解不够好,但我认为它也不适合(或者也许我错了,有人可能会对我说不同的话?)
- 我不能使用SetTimeout,因为它应该在这个特定的动画中阻止函数调用
如何解决此问题?
// Pushes circles aside when some other circle leans on these circles (on zoom in)
var moveCirclesAside = function(circle1, circleToSkip, groupOfMoves) {
var count = circles.length;
for (var i = 0; i < count; i++) {
// Skip the same circle
if (i == circle1.i) {
continue;
}
// Also skip the circle which was intended not to move any further
if (circleToSkip != null && i == circleToSkip.i) {
continue;
}
// Get second circle
var circle2 = circles[i];
// Calculate a distance between two circles
var dx = circle2.x - circle1.x;
var dy = circle2.y - circle1.y;
var distance = Math.sqrt((dx * dx) + (dy * dy));
// If circles already collided need to do some moving...
if (distance <= circle1.r + circle2.r + OD.config.circleSpacing) {
// Get collision angles
var angle = Math.atan2(dy, dx);
var sine = Math.sin(angle);
var cosine = Math.cos(angle);
// Some circle position calculation
var x = OD.config.circleSpacing;
var xb = x + (circle1.r + circle2.r);
var yb = dy * cosine - dx * sine;
// Save each state (move) of any circle to the stack for later rollback of the movement
groupOfMoves.push(copyCircleByVal(circle2));
// Move the circle
circle2.x = circle1.x + (xb * cosine - yb * sine);
circle2.y = circle1.y + (yb * cosine + xb * sine);
// Make sure that circle won't go anywhere out of the canvas
adjustCircleByBoundary(circle2);
// If moved circle leans against some other circles make sure that they are moved accordingly
// And such related moves must be grouped for correct rolback of moves later - so we pass 'groupOfMoves' var
moveCirclesAside(circle2, circle1, groupOfMoves);
}
}
};
这种溢出并不奇怪,因为算法在迭代时会增加堆栈,但退出条件是不可预测的,操作没有严格本地化(它们对附近的圆圈有连锁效应),因此处理时间会很混乱。
我会重新考虑这个算法。考虑寻找两个最接近的圆,如果它们相距超过给定阈值,则中止。否则,将它们稍微分开并重复。
1) 由于需要的操作数量未知,我无法实现迭代;
好吧,我没有看过你的代码,但一般避免线性递归(这里有一个线性递归)看起来是这样的:
while (1 == 1) {
if (breakcondition)
break;
doSomeCode()
}
因此,您不必像for
-循环那样知道迭代的确切次数。
您不需要知道制定迭代解决方案所需的数量或操作。重点是用自己的JavaScript堆栈替换JavaScript堆栈。查看此答案以查看如何实现它的示例:链接
您可以在JavaScript中将Array对象用作堆栈,因为它支持push()
和pop()
。
附言:正如Jim的回答所暗示的,你通常可以找到一个不需要这么多递归级别的算法。
尽量确保递归步骤只针对大于基本情况的情况执行。例如在这里的快速排序:
function qsort(k){
if(k == []){
return k;
}
if(k.length == 1){
return k;
}
//pick random pivot
var p = Math.floor(Math.random()*k.length);
console.log("pivot is" + p + "'n");
//set left and right iter
var l = 0; var r = k.length - 1;
while( l < r){
console.log('hi'n');
//move l until its element is bigger than pivot
while(k[l] < k[p] && l < k.length) {
l++;
console.log('h1i'n');
}
//move r until its element is smaller than pivot
while(k[r] > k[p] && r >= 0) {r--;
console.log('h2i'n');
}
//swap k[l] with k[r]
var temp = k[l]; k[l] = k[r]; k[r] = temp;
}
if(l == r){
//swap k[l] with k[p]
temp = k[l]; k[l] = k[p]; k[p] = temp;
}
var lk = k.slice(0,p); var rk = k.slice(p,k.length);
console.log(lk);
console.log(rk);
if(lk.length > 1){
lk = qsort(lk);
}
if(rk.length > 1){
rk = qsort(rk);
}
result = lk.concat(rk);
console.log(result);
return result;
}
var k = [23,245,67,34,24];
var result = qsort(k);
console.log(result);
//document.write(result);
如果您使用的不是lk.length > 1
,而是lk != []
之类的东西,或者没有进行检查,它有时会给出超出调用堆栈大小的错误,有时会根据选择的枢轴而起作用。
有一个包可以解决递归堆栈溢出问题。
https://github.com/facing-dev/recursive-free
- 是什么让一个“;Uncaught RangeError:超过了最大调用堆栈大小“;错误(Chrome,在其他浏览器中显示
- 超过了async.detect最大调用堆栈大小
- 如何远程检查JavaScript应用程序的函数调用堆栈
- 超过了最大调用堆栈大小,循环无限
- 超过了最大调用堆栈大小.递归标签
- 日志:未捕获的范围错误:超过了最大调用堆栈大小
- 未捕获的范围错误:setTimeout()超过了最大调用堆栈大小
- JavaFX+WebView/Javascript:setTimeOut不起作用调用堆栈来自Java
- JavaScript继承:未捕获的范围错误:超过了最大调用堆栈大小
- 使用$cookies和$stateChangeStart检查sessionID是否超过了最大调用堆栈
- jQuery捕获"RangeError:超过了最大调用堆栈大小“;
- 设置这个.RangeError:超过了最大调用堆栈大小
- 收到“范围错误: 超出最大调用堆栈大小”错误
- 递归 - 测试最大堆栈大小时,调用堆栈无法弹出
- 轮询 ajax 函数超出调用堆栈
- Chrome RangeError:使用jQuery$.map时超过了最大调用堆栈大小
- 要求JS 2.1.9引起“;最大调用堆栈"使用Grunt时出错
- Chrome/jQuery未捕获范围错误:超过了最大调用堆栈大小(函数循环)
- 超过了最大调用堆栈大小-没有明显的递归
- 警告:字体加载过程中出错:轨道上的PDFJS超过了最大调用堆栈大小错误