jQuery / JavaScript:当tab变为非活动状态时,我的递归setTimeout函数会加速

时间:2011-07-08 01:24:51

标签: javascript jquery recursion settimeout performance

我正在构建的这个jQuery幻灯片插件中有一个奇怪的小困境。

这没什么特别的,我迄今为止编写的代码工作得很好但是我注意到当我离开网站运行并切换到新标签并继续浏览其他标签中的网页时(Chrome for Mac)在我的情况下)当我回到我的网站时,setTimeout呼叫似乎加速了,而不是等待计时器完成火灾事件,它会持续发射。

这是我的(简化)代码:

var timer;
var counter;
var slides; // collection of all targeted slides.

// animate to the next slide
function nextSlide() {

    // stop timer
    methods.stopTimer();

    // increase counter
    counter++;
    if ( counter > slides.length-1 ) { counter = 0; } // if counter is greater than the amount of slides, back to the start.

    // inner = container to be animated
    // in the complete callback restart the timer.
    inner.animate({
        'left': '-'+slides.eq( counter ).position().left
    }, {
        duration : settings.animationSpeed,
        easing  : 'easeInOutExpo',
        complete : startTimer()
    });


}
// timer functions.
function startTimer() {
    if ( timer === '' ) {
        timer = setTimeout( function() {
            nextSlide();
        } , 3000 );
    }
}
function stopTimer() {
    clearTimeout( timer );
    timer = '';
}

所以应该发生的是,在动画结束时,计时器会重新附加另一个setTimeout调用,以便它成为一个连续的幻灯片(这样就可以正常工作,直到你离开标签。

一旦你离开标签并返回带幻灯片显示的标签,似乎3000 ms计时器已被缩减以立即调用,现在动画结束时,下一个计时器开始时没有任何延迟。

关于为何如何解决这个问题的任何想法都将不胜感激。

感谢阅读,

Jannis

2 个答案:

答案 0 :(得分:6)

某些浏览器(如Chrome)会在标签变为非活动状态时大幅减慢定期计时器,然后当标签再次激活时,它们会尝试“赶上”以便发生相同数量的实际计时器事件。所有我能想到的解决方法是让你在选项卡处于非活动状态时完全停止幻灯片放映,并在活动结束时再次启动它。

答案 1 :(得分:2)

您是否尝试过间隔而不是超时?也是为了递归,只需将nextSlide()函数作为自己的回调调用:

var counter = 1;

// animate to the next slide
function nextSlide() {

    // increase counter
    counter++;

    // if counter is greater than the amount of slides, back to the start.
    counter =  ( counter > slides.length-1 ) ? 0 : counter;

    // inner = container to be animated
    // in the complete callback restart the timer.
    inner.animate(
    {
        'left': '-' + slides.eq( counter ).position().left
    }, 
    {
        duration : settings.animationSpeed,
        easing  : 'easeInOutExpo',
        complete : nextSlide()
    });

}

然后,这只是启动和停止间隔的问题:

var slideshow;
function startSlideshow()
{
    slideshow = setInterval(nextSlide(),3000);
}

function stopSlideshow()
{
    clearInterval(slideshow);
    inner.stop();
}