Run a function in timeout looping

Go To StackoverFlow.com

0

I have the following code:

// After 8 seconds change the slide...
        var timeout = setTimeout("changeSlide()", 8000);

        $('div.slideshow').mouseover(function() {

            // If the user hovers the slideshow then reset the setTimeout
            clearTimeout(timeout);
        });

        $('div.slideshow').mouseleave(function() {

            clearTimeout(timeout);
            var timeout = setTimeout("changeSlide()", 8000);

        });

What I want to happen is make the function changeSlide run EVERY 8 seconds in a loop unless someone hovers the slideshow div. When they remove the cursor then do the timeout again!

However the loop only happens once and the hover doesn't stop the timeout or start it again :/

EDIT:

This loops great but the hover on and off causes the function to run multiple times:

// After 8 seconds change the slide...
        var timeout = setInterval(changeSlide, 2000);

        $('div.slide').mouseover(function() {

            // If the user hovers the slideshow then reset the setTimeout
            clearInterval(timeout);
        });

        $('div.slide').mouseleave(function() {

            clearInterval(timeout);
            var timeout = setInterval(changeSlide, 2000);

        });
2012-04-05 15:15
by Cameron


1

You have a couple issues here. First off, when you set a timeout, you need to store the return of that function call into a variable if you potentially want to stop it.

    var slide_timer = setTimeout(changeSlide, 8000);

Second, when you call clearTimeout (rather than clearInterval), you need to pass it an argument. What argument? That variable you stored when you called setTimeout

        clearTimeout(slide_timer);

Third, when you use setTimeout, it only fires once. setInterval will continue to fire, then you'd use clearInterval to stop it.

There is an issue in timing with using intervals rather than timeouts. The browser treats them subtly differently, and it may be important to your code to know the difference and use the proper method. If you use intervals, since they only fire once, you'll have to re-establish the timeout every time it fires.

var slide_timer = setTimeout(function () {
    changeSlide();
    var slide_timer = setTimeout(changeSlide, 8000);
}, 8000);

OR

var slide_timer = setTimeout(changeSlide, 8000);
...
function changeSlide() {
   ... your code ...
    var slide_timer = setTimeout(changeSlide, 8000);
}

(I prefer the former method)

And lastly, whether you use timeouts or intervals, don't pass a string to setTimeout, pass a function reference. See the sample code above, or like this:

var slide_timer = setTimeout("changeSlide()", 8000); // <--- DON'T
var slide_timer = setTimeout(changeSlide, 8000);     // <--- DO
var slide_timer = setTimeout(function () {           // <--- DO
    changeSlide() ;
    // other script
}, 8000); 

Putting it all together:

// After 8 seconds change the slide...
    var slide_timer = setTimeout(changeSlide, 8000);
    $('div.slideshow').hover(function() {
        // If the user hovers the slideshow then reset the setTimeout
        clearTimeout(slide_timer);
    }, function() {
        slide_timer = setInterval(changeSlide, 8000);
    });

Documentation

2012-04-05 15:29
by Chris Baker


1

When you specify setTimeout (or setInterval), it returns a value that is then used for clearTimeout and clearInterval. Correct usage is as follows:

var timeout = setTimeout(changeSlide, 8000);
clearTimeout(timeout);

Also note I am using clearTimeout, not clearInterval.

You'll also notice that I did not put quotes around 'changeSlide', and that I dropped the parens. When passing a string to setTimeout, eval() is used. eval() is, in general, recommended to be avoided. So, instead, we pass it the direct reference to the function (without quotes). We do not use parens, because that would actually call changeSlide() right away, instead of deferring execution to setTimeout (and would pass, as an argument to setTimeout, the result of changeSlide())

EDIT: To get it to run continously, you have to call setTimeout again after each changeSlide call. setTimeout runs once. As an alternative, you can use setInterval, which automatically repeats. The one caveat to setInterval is that if the interval is too short and the callback it calls takes a long time to run, you can end up with a bunch of intervals queued up to execute one after another, without delay. An 8 second interval would likely not face this problem.

EDIT 2:

var timeout;
var changeSlide = function(){
   // do something to change slides
   clearTimeout(timeout);
   timeout = setTimeout(changeSlide, 8000);
}

// queue up the first changeSlide, all others happen inside changeSlide
timeout = setTimeout(changeSlide, 8000);

$('div.slideshow').mouseleave(function()  {
    clearTimeout(timeout);
    var timeout = setTimeout(changeSlide, 8000);
});
2012-04-05 15:18
by Matt
Cool I've changed the code based on your answer but it still doesn't loop the timeout - Cameron 2012-04-05 15:23
The key is to call setTimeout again at the end of each changeSlide, it queues up the next change. You can use setInterval as well, works repeatedly, instead of onc - Matt 2012-04-05 15:25


0

I think you need setInterval and not setTimeout, since:

setTimeout(expression, timeout); runs the code/function once after the timeout

setInterval(expression, timeout); runs the code/function in intervals, with the length of the timeout between them

2012-04-05 15:23
by ericosg


0

In the end this worked the best (but I won't accept this as my answer as it was others who helped me get to this point)

// After 8 seconds change the slide...
    var slide_timer = setInterval(changeSlide, 2000);
    $('div.slideshow').hover(function() {
        // If the user hovers the slideshow then reset the setTimeout
        clearInterval(slide_timer);

    }, function() {
        slide_timer = setInterval(changeSlide, 2000);
    });
2012-04-05 15:40
by Cameron
Heh, I don't use jQuery, but I felt like I wasn't using the hover function right. Good to know... I'll probably forget though. : - Chris Baker 2012-04-05 15:43


0

Your issue may be the mouseover event. The mouseover event bubbles, so if you have a nested HTML structure, then the event may be called more than once. If you are using jQuery, you should use the mousenter event, which will only get called once for the element.

On a different note, instead of using setInterval use a setTimeout pattern. Something like this:

    //Immediately Invoked Function Expression that gets called immediately
    (function() {
        //Make the initial call to your setTimeout function
        repeat();
        //Function will constantly be called
        function repeat() {
            setTimeout(function() {
                //(Put your conditional logic here)
                console.log('test');
                repeat();
            }, 2000);
        }
    })();
2012-04-05 15:57
by Greg Franko
Ads