【问题标题】:Watching setTimeout loops so that only one is running at a time观看 setTimeout 循环,以便一次只运行一个
【发布时间】:2010-04-29 18:10:46
【问题描述】:

我正在 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 来清除它。

【问题讨论】:

    标签: javascript loops


    【解决方案1】:

    你应该做的是保存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()。好的部分是它会立即生效,您不需要进行任何轮询或其他任何复杂的操作。

    【讨论】:

    • 像往常一样,以我的编码技能,有一个更简单的方法来解决它。出色的答案,约翰。谢谢!
    • 好的,我打嗝了。我正在更新上述内容以反映这一点。
    • 我更新了我的帖子,增加了一个问题。问题。我相信,在现有循环有机会查看它是否为空之前重置超时变量与我有某种冲突。
    • 摆脱“continueCheck”的想法。淡入和淡出函数不应该有任何关于检测它们何时被取消的逻辑。如果他们被取消,他们根本不会被首先调用。如果您完全删除该功能,它应该可以工作。
    • 约翰...谢谢。不过还是有问题。通过更多的 console.log()ing,我发现它只是没有停止初始循环。因此,它会在每次单击我的导航项时复合它们。如果我点击 3 个项目,我最终会同时运行 3 个循环。在我重新启动循环的同一个点击事件中清除超时是否有问题?
    猜你喜欢
    • 2015-02-05
    • 2011-12-13
    • 2017-01-24
    • 2018-05-02
    • 1970-01-01
    • 2011-11-02
    • 2013-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多