Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript recursion: Maximum call stack size exceeded

I have a recursive function for moving some circles on a canvas. Overed circle is enlarged (zoom in) and all the other circles is pushed away. Pushed circles push other circles and so on until zooming is complete.

I get an error "Maximum call stack size exceeded", and I understand the problem, but I just don't know how to solve it... I found three possible solutions for solving recursion problems in general:

  1. Change recursion to iteration
  2. Use memoization
  3. Use SetTimeout

But I think that I can use none of them:

  1. I can not implement iteration because of unknown count of operations needed
  2. I don't understand memoization well enough, but I think it does not fit either (or maybe I'm wrong and someone could told me differently?)
  3. I can not use SetTimeout, because it should be blocking function calls at this particular animation.

How do I fix this problem?

// 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);
        }
    }
};
like image 347
fizis Avatar asked Feb 29 '12 10:02

fizis


People also ask

How do I fix maximum call stack size exceeded?

The call stack is limited in size, and when it's exceeded, the RangeError is thrown. This can happen when a deeply nested function is called, or when a lot of new variables are created. The most common way to fix this error is to reduce the number of function calls, or to limit the number of variables that are created.

What is the maximum call stack size in JavaScript?

Without any local variables, each function call takes up 48 bytes during the execution, and you are limited to less than 1MB for all local function frames.

How do you fix uncaught RangeError maximum call stack size exceeded see JavaScript console for details?

The "RangeError: Maximum call stack size exceeded" error occurs when a function is called so many times that the invocations exceed the call stack limit. To solve the error, specify a base case that has to be met to exit the recursion.

What does it mean when maximum call stack size exceeded?

The JavaScript RangeError: Maximum call stack size exceeded is an error that occurs when there are too many function calls, or if a function is missing a base case.


2 Answers

1) I can not implement iteration because of unknown count of operations needed;

Well, I have not looked at your code, but a general avoidance of linear recursion (you have a linear one here) looks like this:

while (1 == 1) {
    if (breakcondition)
        break;
    doSomeCode()
}

So you do not have to know the exact number of iterations like in the for- loop case.

like image 100
Stasik Avatar answered Oct 11 '22 20:10

Stasik


It doesn't surprise this overflows because the algorithm grows the stack as it iterates but the exit condition is unpredictable, actions are not tightly localized (they have knock-on effects to nearby circles), so processing time will be chaotic.

I would reconsider the algorithm. Consider finding the two closest circles, if these are further apart than a given threshold apart, abort. Otherwise move them apart a little and repeat.

like image 26
Jim Blackler Avatar answered Oct 11 '22 21:10

Jim Blackler