setTimeout ускоряется благодаря нескольким вкладкам - PullRequest
6 голосов
/ 24 мая 2011

У меня проблема setTimeout, аналогичная этой .Но это решение не помогает мне, так как я не могу использовать php в своем файле.

На моем сайте есть слайдер со списком изображений, которые перемещаются каждые 8 ​​секунд. Однако, когда я открыл несколько вкладокв браузере, а затем снова переключиться, он сходит с ума.Ползунок начинает перемещать изображения одно за другим немедленно, без 8-секундной задержки.

Я вижу это только в Chrome и последнем Firefox.

** РЕДАКТИРОВАТЬ: Я проверил сconsole.log () и setTimeout возвращают одно и то же число до и после clearTimeout.Не уверен почему.Может быть, это тоже как-то связано с этим?**

РЕДАКТИРОВАТЬ 2: Я добавил скрипку: http://jsfiddle.net/Rembrand/qHGAq/8/

Код выглядит примерно так:

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');
   }
}

Ответы [ 7 ]

13 голосов
/ 10 августа 2011

Из документации jQuery :

Из-за природы requestAnimationFrame () вы никогда не должны ставить анимацию в очередь с помощью цикла setInterval или setTimeout.Чтобы сохранить ресурсы ЦП, браузеры, поддерживающие requestAnimationFrame, не будут обновлять анимацию, когда окно / вкладка не отображается.Если вы продолжите ставить анимации в очередь с помощью setInterval или setTimeout, когда анимация приостановлена, все анимации в очереди начнут воспроизводиться, когда окно / вкладка восстановит фокус.Чтобы избежать этой потенциальной проблемы, используйте функцию обратного вызова вашей последней анимации в цикле, или добавьте функцию к элементам .queue () , чтобы установить тайм-аут для запуска следующей анимации.

11 голосов
/ 26 мая 2011

Я наконец нашел свой ответ, и это совсем не то, что я ожидал. Похоже, виновником является janu .animate (), который я использую для перемещения изображений в слайдере.

Я вычисляю и перемещаю свои позиции изображений следующим образом:

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

Теперь проблема заключается в том, что в некоторых браузерах после переключения на новую вкладку и обратно функция .animate () jQuery сохраняет анимацию и запускает их все сразу. Поэтому я добавил фильтр для предотвращения очередей. Это решения приходят от CSS-Tricks.com :

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

Первый слайд, который вы видите, когда возвращаетесь, может показаться немного нервным, но он лучше, чем у суперскоростной карусели, существовавшей ранее.

Скрипка с полным кодом здесь

1 голос
/ 11 сентября 2011

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

Так что-то вроде этого:

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

Это может работать не во всех случаях (в зависимости от времени), но я надеюсь, что это кому-нибудь поможет!

1 голос
/ 09 сентября 2011

Существует более простой способ использования свойства очереди jquery animate:

$(this).animate({
    left: '+=100'
}, {duration:500, queue:false});
0 голосов
/ 14 сентября 2011

Какую версию jQuery вы используете?По-видимому, эта проблема была «исправлена» в версии 1.6.3 - они отменили изменение, вызвавшее это.Обсуждения здесь и здесь .

Хотя эту проблему, скорее всего, придется решать в будущем, кажется, что мы сейчас не в курсе.

0 голосов
/ 24 мая 2011

Я подозреваю, что браузер ставит в очередь события ввода, такие как «щелчок», но запускает их только тогда, когда вкладка, где происходит событие, имеет фокус.

Возможно, вам следует попробовать вызвать обратные вызовы по клику напрямую, вместо использования trigger('click').

Примерно так:

spotlight: {
    i: 0,
   timeOutSpotlight: null,
   clickFunc: function(element) {

       // do stuff here to count and move images

       // 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);
   },

   init: function()
   {

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

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

           spotlight.clickFunc(this);
       });

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

   animate: function(i)
   {
       var element = $('#spotlight .controls li:eq('+spotlight.i+') a.next');
       spotlight.clickFunc(element);
   }
}
0 голосов
/ 24 мая 2011

Вы также должны думать, что используете clearTimeout.

Когда вы вызываете функцию setTimeout, она возвращает идентификатор, вы можете сохранить этот идентификатор в переменной типа

timeoutID = setTimeout(function () {
                spotlight.animate(spotlight.i);
            }, 8000);

и перед установкой нового тайм-аута вы можете вызвать такую ​​функцию, как

clearTimeout(timeoutID)
...