观察setTimeout循环,以便一次只运行一个

时间:2010-04-29 18:10:46

标签: javascript loops

我正在jQuery中创建一个内容循环器。共5项。第1项淡入,暂停10秒,淡出,然后第2项淡入。重复。

足够简单。使用setTimeout我可以调用一组创建循环的函数,并将无限期地重复该过程。

我现在想通过点击导航元素直接跳转到其中一个内容项来添加中断此旋转器的功能。

我最初开始沿着不断地(例如每半秒)ping一个变量的路径,检查导航元素是否被点击,如果是,则放弃循环,然后根据项目重新启动循环点击了。

我遇到的挑战是如何通过计时器实际ping一个变量。解决方案是深入研究JavaScript闭包......这有点超出我的想法,但绝对需要深入研究。

然而,在此过程中,我提出了一个替代选项,实际上似乎在性能上更好(理论上至少)。我有一个样本在这里运行:

http://jsbin.com/uxupi/14

(它正在使用console.log,因此运行fireBug)

示例脚本:

$(document).ready(function(){

var loopCount = 0;

$('p#hello').click(function(){
  loopCount++;
  doThatThing(loopCount);
})

function doThatOtherThing(currentLoopCount) {  
console.log('doThatOtherThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
  setTimeout(function(){doThatThing(currentLoopCount)},5000)
 }
}  


function doThatThing(currentLoopCount) {
 console.log('doThatThing-'+currentLoopCount);
 if(currentLoopCount==loopCount){
   setTimeout(function(){doThatOtherThing(currentLoopCount)},5000);
 }
}

}) 

逻辑是每次点击触发元素都会启动循环,向自身传递一个等于全局变量当前值的变量。该变量在循环中的函数之间来回传递。

每次单击触发器也会增加全局变量,以便循环的后续调用具有唯一的局部变量。

然后,在循环内,在调用每个循环的下一步之前,它会检查它所具有的变量是否仍然与全局变量匹配。如果没有,它知道一个新的循环已经被激活,所以它只是结束现有的循环。

对此的想法?有效的方案?更好的选择?注意事项?危险?

更新:

我正在通过clearTimeout选项使用John的建议。

然而,我无法让它发挥作用。逻辑是这样的:

var slideNumber = 0; 

var timeout = null;


function startLoop(slideNumber) {
    //... code is here to do stuff here to set up the slide based on slideNumber...
    slideFadeIn()
}

function continueCheck() {
    if (timeout != null) {
        // cancel the scheduled task.
        clearTimeout(timeout);
        timeout = null;
        return false;
    } else {
        return true;
    }
};

function slideFadeIn() {
    if (continueCheck){
        // a new loop hasn't been called yet so proceed...

        $mySlide.fadeIn(fade, function() {
            timeout = setTimeout(slideFadeOut,display);
        }); 
    }       
};


function slideFadeOut() {
    if (continueCheck){
        // a new loop hasn't been called yet so proceed...

        slideNumber=slideNumber+1;

        $mySlide.fadeOut(fade, function() {
            //... code is here to check if I'm on the last slide and reset to #1...
            timeout = setTimeout(function(){startLoop(slideNumber)},100);
        });

     }   
};


startLoop(slideNumber);

循环的上述踢法。

然后我有导航项目,点击后,我希望上面的循环停止,然后用新的开始幻灯片重新启动:

$(myNav).click(function(){
    clearTimeout(timeout);
    timeout = null;
    startLoop(thisItem);
})

如果我从click事件中注释掉'startLoop ...',它确实会停止初始循环。但是,如果我离开最后一行,它实际上并不会停止初始循环。为什么?会发生的是,两个循环似乎并行运行一段时间。

所以,当我点击导航时,会调用clearTimeout,清除它。

1 个答案:

答案 0 :(得分:6)

你应该做的是保存setTimeout返回的句柄并用clearTimeout清除它以中断旋转器。

var timeout = null;

function doThatThing() {
    /* Do that thing. */

    // Schedule next call.
    timeout = setTimeout(doThatOtherThing, 5000);
}

function doThatOtherThing() {
    /* Do that other thing. */

    // Schedule next call.
    timeout = setTimeout(doThatThing, 5000);
}

function interruptThings() {
    if (timeout != null) {
        // Never mind, cancel the scheduled task.
        clearTimeout(timeout);
        timeout = null;
    }
}

点击导航元素后,只需拨打interruptThings()即可。好的部分是它会立即生效,你不需要做任何轮询或其他任何复杂的事情。

相关问题