代码之家  ›  专栏  ›  技术社区  ›  DA.

监视setTimeout循环,以便一次只运行一个

  •  1
  • DA.  · 技术社区  · 16 年前

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

    现在我想添加一种能力,通过单击导航元素直接跳转到一个内容项,随时中断这个旋转器。

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

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

    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事件中注释掉“startoop…”,它确实会停止初始循环。但是,如果我把最后一行放进去,它实际上不会停止初始循环。为什么?结果是两个循环似乎并行运行了一段时间。

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

    1 回复  |  直到 16 年前
        1
  •  6
  •   John Kugelman Michael Hodel    16 年前

    您应该做的是保存 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() . 好的方面是它会立即生效,你不需要做任何投票或其他复杂的事情。