setInterval не работает должным образом в Chrome - PullRequest
9 голосов
/ 05 августа 2011

У меня есть объект слайд-шоу, выполненный на заказ, для выполнения обычных вещей, которые имя указывает на веб-сайте. Все работает хорошо, за исключением случаев, когда я переключаю вкладки в Chrome и возвращаюсь на вкладку веб-сайта. Когда это происходит, слайд-шоу сходит с ума и начинает исчезать изображения без учета заданного интервала setInterval. Не могу найти ничего связанного с этим, поэтому я хотел бы, по крайней мере, знать, если это проблема с кодом или проблема с программным обеспечением.

Вот код (используется с 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();

});

Ответы [ 4 ]

11 голосов
/ 05 августа 2011

Я бы предпочел использовать setTimeout () несколько раз по сравнению с setInterval () - так много вещей может пойти не так с setInterval (), и вы не знаете, насколько загружен браузер и реалистичен ли интервал.

Браузеры не соблюдают выбранный вами тайм-аут или интервал точно.Это в основном для безопасности;чтобы предотвратить поток событий, мешающих браузеру нормально функционировать.Chrome лучше относится к более точному соблюдению таймеров, хотя он все же значительно замедляет их, когда вкладка находится в фоновом режиме (например, см. Этот ответ ).

Если вы установили новыйтаймер с setTimeout во время вашего существующего вызова slideshow.action (), тогда вы не получите очередей событий, когда ваш браузер не может идти в ногу, но все равно будет хорошо и быстро, когда браузер сможет это сделать.

Вы все равно сможете остановить таймер, используя идентификатор таймера, этот идентификатор будет часто меняться.

8 голосов
/ 05 августа 2011

Chrome (и, по-видимому, также последние версии Firefox) уменьшают скорость setInterval, когда вкладка находится в фоновом режиме, чтобы улучшить производительность переднего плана. Это, вероятно, имеет наибольшее значение, когда на фоновых страницах быстро запускаются анимации на основе таймера Когда страница возвращается на передний план, она «пытается» наверстать упущенное и выполняет setInterval вызовы намного быстрее, чем обычно.

Обходные пути:

  1. Увеличьте время setInterval, чтобы Chrome не связывался с ним (вам нужно посмотреть, что это за время).
  2. Остановите интервальный таймер, когда страница переходит в фоновый режим (нет необходимости запускать слайды, когда она все равно не видна) - затем снова запустите его, когда страница выйдет на передний план.
  3. Используйте повторное setTimeout вместо setInterval с некоторым типом повторного setTimeout, подобным этому:

Код:

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

Подобный пост здесь .

2 голосов
/ 05 августа 2011

Скорее всего, вы не должны ожидать, что setInterval будет точным.На вашем месте я бы проверил правильность интервала, сравнив предыдущее время с текущим.Это должно сделать код более надежным.

0 голосов
/ 11 мая 2016

Была похожая проблема с хромом

Как я решил эту проблему. Сначала запишите переменную mktime, а затем просто вычтите ее из текущего времени. Пример:

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
}
...