setInterval not working properly on Chrome
Asked Answered
S

5

15

I have a custom made slideshow object to perform the usual stuff the name indicates on a website. It all works well except when I switch tabs in Chrome and come back to the website tab. When that happens, the slideshow goes nuts and starts fading the images disregarding the setInterval interval given. Can't find anyhing related to this, so I'd like to at least know if it's a problem with the code or a software issue.

Here's the code (being used with jQuery) :

$(function() {

    // slideshow
    var slideshow = {
        id : false,
        current : 0,
        count : 0,
        interval : false,
        init : function(data) {
            if (!data)
                return false;

            $.each(data, $.proxy(
                function(index, value) {
                    this[index] = data[index];
                }, this)
            );

            this.count = this.images.length;

            for (x=1;x<=this.count;x++)
                $('#slider ul.nav').append('<li></li>');

            $('#slider ul.nav li').live('click', function()
            {
                slideshow.click(this);
            });

            $('#slider ul.nav li:eq(0)').addClass('on');
            $('#slider ul.nav').css('width', (15*this.count)+'px');

            return true;
        },
        start : function () {
            slideshow.id = setInterval(function() { slideshow.action(); }, slideshow.options.interval);
        },
        stop : function() {
            clearInterval(slideshow.id);
        },
        action : function() {
            slideshow.current < (slideshow.count-1) ? slideshow.current++ : slideshow.current = 0;

            $('#slider img').fadeOut('normal', function() {
                $('#slider img').attr('src', slideshow.images[slideshow.current].url);
                $('#slider ul.nav li').removeClass('on');
                $('#slider ul.nav li:eq('+slideshow.current+')').addClass('on');
                $('#slider div.title').html(slideshow.images[slideshow.current].title);
                $('#slider div.description').html(slideshow.images[slideshow.current].description);
                $('#slider a.more').attr('href', slideshow.images[slideshow.current].target);
            }).fadeIn('normal');

            return true;
        },
        click : function(o) {
            slideshow.stop();

            var index = $('#slider ul.nav li').index(o);
            slideshow.current = index;

            $('#slider img').fadeOut('normal', function() {
                $('#slider img').attr('src', slideshow.images[index].url);
                $('#slider ul.nav li').removeClass('on');
                $(o).addClass('on');
                $('#slider div.title').html(slideshow.images[index].title);
                $('#slider div.description').html(slideshow.images[index].description);
                $('#slider a.more').attr('href', slideshow.images[index].target);
            }).fadeIn('normal');

            slideshow.start();
            return true;
        },
    };

    slideshow.init(slider);
    slideshow.start();

});
Sedition answered 5/8, 2011 at 5:13 Comment(0)
F
12

I'd favour using setTimeout() repeatedly over using setInterval() - so many things can go wrong with setInterval() and you don't know how busy the browser is and whether the interval is realistic.

Browsers don't honour your chosen timeout or interval exactly. This is mainly for security; to prevent a flood of events from messing with the browser's ability to function normally. Chrome is better about honouring timers more accurately, though it does still slow them down significantly when a tab is in the background (see this answer), for example.

If you set a new timer with setTimeout during your existing call to slideshow.action(), then you won't get events queuing up when your browser can't quite keep up, but it will still go nice and quickly when the browser is able to do so.

You will still be able to stop the timer using the timer ID, that ID will just change often.

Firstborn answered 5/8, 2011 at 5:56 Comment(2)
Tried setTimeout() without any success. The issue with Chrome tabs still happens even if I tell the script to make the difference of timestamps and adjust the interval (using console.log I could see that it's never changed, wich makes me believe Chrome freezes the tab proccess or something).Sedition
See this answer: #6032929Firstborn
B
14

Chrome (and apparently the latest versions of Firefox too) reduce the speed of setInterval when the tab is in the background to improve foreground performance. This probably matters the most when there are fast running timer-driven animations in background pages. When the page comes back to the foreground, it "tries" to catch up and runs a bunch of setInterval calls much faster than they would normally run.

The work-arounds are:

  1. Lengthen the time of the setInterval so Chrome won't mess with it (you'd have to look up what that time is).
  2. Stop your interval timer when the page goes in the background (no need to run slides when it's not visible anyway) - then start it up again when the page comes to the foreground.
  3. Use repeated setTimeout instead of setInterval with some type of repeated setTimeout like this:

Code:

function nextSlide() {
    // show next slide now
    // set timer for the slide after this one
    setTimeout(function() {
        nextSlide();       // repeat
    }, xxx)
}

Similar post here.

Byram answered 5/8, 2011 at 5:17 Comment(0)
F
12

I'd favour using setTimeout() repeatedly over using setInterval() - so many things can go wrong with setInterval() and you don't know how busy the browser is and whether the interval is realistic.

Browsers don't honour your chosen timeout or interval exactly. This is mainly for security; to prevent a flood of events from messing with the browser's ability to function normally. Chrome is better about honouring timers more accurately, though it does still slow them down significantly when a tab is in the background (see this answer), for example.

If you set a new timer with setTimeout during your existing call to slideshow.action(), then you won't get events queuing up when your browser can't quite keep up, but it will still go nice and quickly when the browser is able to do so.

You will still be able to stop the timer using the timer ID, that ID will just change often.

Firstborn answered 5/8, 2011 at 5:56 Comment(2)
Tried setTimeout() without any success. The issue with Chrome tabs still happens even if I tell the script to make the difference of timestamps and adjust the interval (using console.log I could see that it's never changed, wich makes me believe Chrome freezes the tab proccess or something).Sedition
See this answer: #6032929Firstborn
I
2

Most likely, you shouldn't expect setInterval to ever be accurate. If I were you, I would check that the interval is correct by comparing the previous interval time to the current one. That should make the code more robust.

Immovable answered 5/8, 2011 at 5:17 Comment(0)
A
0

There was a similar problem with chrome

As I have solved this problem. At the start, write down mktime variable, and then simply subtracted from the current time. Example:

var values = {};

function mktime(){
 var date = new Date();
 return Math.floor(date.getTime()/1000);
}
function getTime(string){
  var splitContent = string.split(/\:/g);
  var hours = parseInt(splitContent[0]) * 60 * 60;
  var minutes = parseInt(splitContent[1]) * 60;
  var seconds = parseInt(splitContent[2]);                          
  return hours + minutes + seconds;
}
function startTimer(time){

 values.startMkTime = mktime();
 values.startTime = getTime(time);
 setInterval(process(),1000);                       
}

function process(){
   values.currentTime = (mktime() - values.startMkTime) +       o.values.startTime;//new code
}
Audiovisual answered 11/5, 2016 at 9:5 Comment(1)
setInterval(process(), ...) will try to execute the return value of process, which is almost certainly not what you want. setInterval takes a function reference as its first argument (or a string, but not important here).Invaginate
P
0

I found that setInterval was not working if the interval was under a second. i had it set to 500ms and with an xhr call in the callback and it never fired. Worked with chromeDev for android but not the standard version. I set it to a second (1000ms) and it worked fine. It was like chrome for android did not like doing big things in small intervals

Polysynthetic answered 1/8, 2021 at 6:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.