views:

225

answers:

3

Using jQuery, I've build an image/slide rotator. The basic setup is (in pseudocode):

function setupUpSlide(SlideToStartWith){
    var thisSlide = SlideToStartWith;
    ...set things up...
    fadeInSlide(thisSlide)
}

function fadeInSlide(thisSlide){
    ...fade in this slide...
    fadeOutSlide(thisSlide)
}


function fadeOutSlide(thisSlide){
    ...fade out this slide...
    thisSlide.fadeOut(fade, function() {
    var timeout2 = setTimeout(setupUpSlide(nextSlide),100);
    }

I call the first function and pass in a particular slide index, and then it does its thing calling chain of functions which then, in turn, calls the first function again passing in the next index. This then repeats infinitely (resetting the index when it gets to the last item).

This works just fine.

What I want to do now is allow someone to over-ride the slide show by being able to click on a particular slide number. Therefore, if slide #8 is showing and I click #3, I want the recursion to stop and then call the initial function passing in slide #3, which then, in turn, will start the process again.

But I'm not sure how to go about that. How does one properly 'break' a recursive script. Should I create some sort of global 'watch' variable that if at any time is 'true' will return: false and allow the new function to execute?

UPDATE: Added more detailed code showing setTimeout call

+6  A: 

Using recursion to implement a slideshow is probably not a good idea because it will eventually give a stack overflow.

Use timeouts instead.

setTimeout() - executes a code some time in the future

clearTimeout() - cancels the setTimeout()

Or intervals (thanks Ricket for pointing this out!):

The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds).

The setInterval() method will continue calling the function until clearInterval() is called, or the window is closed.

Mark Byers
At some point, however, don't I need the recursion to continue the loop? Ie, if I have 6 slides, I need to go from 1 to 6 and then repeat. Using the above Timeout methods, how does one incorporate the for-loop logic to increment the calls?
DA
@DA: Using timeouts you can create an infinite loop without getting a stack overflow. Each call represents one step in your loop.
Mark Byers
ack. Should have looked at what I already had closer. Turns out we are using a setTimeout function in the last function (that then, in turn calls the first one). I've updated the sample code in the original post. Is that all that's needed to avoid the stack overflow issue?
DA
If so...then I guess the question still remains...how to 'cancel' wherever the current looping cycles is in. For instance, if I'm pausing 10 seconds between each one and I click to 'stop' the current animation immediately rather than waiting the remaining 9 seconds.
DA
@DA: Only one piece of javascript can run at a time. If you put a sleep of 10 seconds in your javascript it will freeze your web app for those 10 seconds - no other javascript will run. If you instead set a timeout for 10 seconds and then let your function return immediately, then your webapp will remain responsive plus you can use clearTimeout to stop the operation before the 10 seconds have passed.
Mark Byers
A: 

instead of indirect recursion, try using a recurring timeout (var timer_id = setInterval(...)) and use clearTimeout when you want to stop it

matei
initTimeout? do you mean setInterval? (and corresponding clearInterval)
Ricket
yes, my mistake
matei
A: 

Here's an easy way to do it. First of all, instead of calling the functions directly, use window.setTimeout(function(){...}) at the end of each function, replacing the ... with the last line (that makes the recursive call). This will prevent the stack overflow.

Second, provide a way to communicate with the loop. Your boolean watch variable is a good idea. It doesn't have to be global, just something the function linked to your click handler and the slideshow functions both have access to--a static class variable, for instance. Watch that variable for changes and break the loop; or, have the variable be the currently set up slide.

Being easy, that doesn't mean this is the best way to do it. For one thing, your JQuery animation calls are asynchronous, and you need to be using their callback functions instead of the way you are doing it here, or all the animations are going to happen at once. You can do all of that in the space of one single function call in one function. JQuery allows chaining your animations, and it also allows you to issue a stop command to any existing animation. I would look into this way of doing it first instead of continuing with the setup you have now.

Plynx