Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setTimeout speeds up with multiple tabs

I’m having a setTimeout problem similar to this one. But that solution doesn't help me since I can’t use php in my file.

My site has a slider with a list of images that move every 8 seconds.However, when I have opened a few tabs in the browser and then switch back again, it goes nuts. The slider proceeds to move the images one after the other immediately without the 8 second timedelay.

I'm only seeing it in Chrome and the latest Firefox.

**EDIT: I checked with console.log() and the setTimeout returns the same number before and after the clearTimeout. Not sure why. Maybe that also has something to do with it? **

EDIT 2: I added a fiddle: http://jsfiddle.net/Rembrand/qHGAq/8/

The code looks something like:

spotlight: {
    i: 0,
   timeOutSpotlight: null,

   init: function()
   {
       $('#spotlight .controls a').click(function(e) {

           // do stuff here to count and move images

           // Don't follow the link
           e.preventDefault();

           // Clear timeout
           clearTimeout(spotlight.timeOutSpotlight);

           // Some stuff here to calculate next item

           // Call next spotlight in 8 seconds
           spotlight.timeOutSpotlight = setTimeout(function () {
                spotlight.animate(spotlight.i);
            }, 8000);
       });

       // Select first item
       $('#spotlight .controls a.next:first').trigger('click');
   },

   animate: function(i)
   {
       $('#spotlight .controls li:eq(' + (spotlight.i) + ') a.next').trigger('click');
   }
}
like image 643
Rembrand Avatar asked May 24 '11 15:05

Rembrand


People also ask

Does setTimeout run multiple times?

The setTimeout() is executed only once. If you need repeated executions, use setInterval() instead. Use the clearTimeout() method to prevent the function from starting.

Does setTimeout affect performance?

No significant effect at all, setTimeout runs in an event loop, it doesn't block or harm execution.

Can setTimeout cause stack overflow?

Set timeout would not cause stack overflow, because it is asynchronous. It will just put the callback to the event queue and not block the execution.

Does setTimeout work asynchronous?

Working with asynchronous functionssetTimeout() is an asynchronous function, meaning that the timer function will not pause execution of other functions in the functions stack.


4 Answers

From the jQuery documentation:

Because of the nature of requestAnimationFrame(), you should never queue animations using a setInterval or setTimeout loop. In order to preserve CPU resources, browsers that support requestAnimationFrame will not update animations when the window/tab is not displayed. If you continue to queue animations via setInterval or setTimeout while animation is paused, all of the queued animations will begin playing when the window/tab regains focus. To avoid this potential problem, use the callback of your last animation in the loop, or append a function to the elements .queue() to set the timeout to start the next animation.

like image 100
davydepauw Avatar answered Oct 23 '22 11:10

davydepauw


I finally found my answer and it’s not at all what I was expecting. It seems the culprit is jQuery’s .animate(), which I use to move the images in the slider.

I calculate and move my images positions with this:

$('.spotlight-inner')
    .animate(
        { left: scrollToVal },
        {duration: 'slow'}
    )
 ;

Now the problem seems to be that in some browsers, after you switch to a new tab and back, jQuery’s .animate() saves up the animations and fires them all at once. So I added a filter to prevent queueing. That solutions comes from CSS-Tricks.com :

$('.spotlight-inner')
    .filter(':not(:animated)')
    .animate(
        { left: scrollToVal },
        {duration: 'slow'}
    )
;

The first slide you see when you go back can act a little jumpy but it’s better than the superspeed carousel from before.

Fiddle with the full code here

like image 41
Rembrand Avatar answered Oct 23 '22 11:10

Rembrand


There is an easier way using the jquery animate queue property:

$(this).animate({
    left: '+=100'
}, {duration:500, queue:false});
like image 1
Jon B Avatar answered Oct 23 '22 12:10

Jon B


I don't know if this will help you, but it helped me with my slideshow. What I did was everytime I called an animation that was supposed to happen at a set interval because of the setTimeout, I called clearQueue() which would get rid of any other animations that had been set to happen. then i'd call the animation. That way when you come back to that tab, you don't have all these animations queued up and it goes crazy. at max you'll only have one set up.

So something like this:

       spotlight.timeOutSpotlight = setTimeout(function () {
            spotlight.clearQueue(); // get rid of other instances of the animation
            spotlight.animate(spotlight.i);
        }, 8000);

It may not work in all cases (depending on timing), but I hope that helps somebody!

like image 1
Grenard Madrigal Avatar answered Oct 23 '22 11:10

Grenard Madrigal