Caballero
Caballero

Reputation: 12101

recursive function and setTimeout() problem

I have a script that draws a bunch of lines on canvas, but it's pretty intense so while rendering freezes browser for a few seconds. I added setTimeout() so that the browser wouldn't freeze and it effectively messed up my script. It's difficult to explain how, so I have two examples online:

Without setTimeout() : http://www.modwebsolutions.com/test1

With setTimeout() : http://www.modwebsolutions.com/test2

Note, that I only change a single line in the whole script, that is line 69:
without setTimeout(): vLoop();
with setTimeout(): setTimeout(vLoop,1);

Upvotes: 0

Views: 752

Answers (3)

musaul
musaul

Reputation: 2341

The problem here, as hinted at by others, is that you are drawing the lines a quadrant at a time. As soon as the SetTimeout method is called and the first vLoop returns, the code carries on running into the next drawVertical which changes all the global variables and so on.

What you need to do is synchronise how you're calling vLoop and how you are changing the globals.

This is basically the solution:

 

Replace ...

drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0); 
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);

... with ...

var q = new Array();
q[0] = [c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y];
q[1] = [c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y];
q[2] = [c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0];
q[3] = [c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0];

drawQuadrant(q, 0);

 

Replace your drawVertical function with ...

function drawQuadrant(q, i)
{
    var r = q[i];

    c__ = r[0];
    step__ = r[1];
    stepInt__ = r[2];
    bigStep__ = r[3];
    xStart__ = r[4];
    xEnd__ = r[5];
    yStart__ = r[6];
    yEnd__ = r[7]; 


    vLoop(q,i);
}

 

change the vLoop function prototype to look like this ...

function vLoop(q,i)

 

and finally replace your recursive vLoop call (from within vLoop) with ...

if ((xStart__ > 0) && (xStart__ < window.innerWidth))
{
    setTimeout( function(){vLoop(q,i)}, 1 );
}
else if (++i < 4)
{
    setTimeout( function(){drawQuadrant(q,i)}, 1 );
}

The last block is where it ensures that the quadrants are not stepping over each other.

Upvotes: 3

Nick Craver
Nick Craver

Reputation: 630379

What's happening is what setTimeout() delays all that execution until later. Unfortunately, by that point your global variables have all moved to their ending positions from the initial loop, since it completed before the first line was drawn.

If you moved your timeout further up (so the shared variables you're using aren't affected until draw time) you could achieve what you're after, for example:

setTimeout(function() {
    drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
    drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
    drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0);
    drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);
});

Then this would work (but it's dangerous, order isn't absolutely garunteed!)

You can see a working example here.

Upvotes: 0

Raynos
Raynos

Reputation: 169383

drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0); 
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);

Your calling 4 recursive functions of vLoop at once. The problem here is that setTimeout is non-blocking where as recursion is blocking. So basically you now have all 4 of these drawVertical functions running in parallel rather then in sequence.

The other problem is that all 4 refer and mess with global state and your entire program breaks.

Upvotes: 0

Related Questions