如何停止 setTimeout 循环?

IT技术 javascript css extjs settimeout
2021-01-18 15:39:11

我正在尝试用图像精灵构建一个加载指示器,我想出了这个功能

function setBgPosition() {
   var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
       Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length)
        {
            setTimeout(run, 200);
        }else
        {
            setBgPosition();
        }
    }
    setTimeout(run, 200);
}

所以输出看起来像这样

http://jsfiddle.net/TTkre/

我不得不使用 setBgPosition(); 在 else 中保持循环运行,所以现在我的问题是如何在我想要 [加载完成] 时停止这个循环?

6个回答

setTimeout返回一个计时器句柄,您可以使用它来停止超时clearTimeout

所以例如:

function setBgPosition() {
    var c = 0,
        timer = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c >= numbers.length) {
            c = 0;
        }
        timer = setTimeout(run, 200);
    }
    timer = setTimeout(run, 200);

    return stop;

    function stop() {
        if (timer) {
            clearTimeout(timer);
            timer = 0;
        }
}

所以你可以把它用作:

var stop = setBgPosition();
// ...later, when you're ready to stop...
stop();

请注意setBgPosition,我没有再次调用自己,而是将其设置c0. 否则,这是行不通的。另请注意,我已用作0超时未挂起时的句柄值;0不是一个有效的返回值,setTimeout所以它是一个方便的标志。

这也是我认为你最好使用setInterval而不是的(少数)地方之一setTimeoutsetInterval重复。所以:

function setBgPosition() {
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c >= numbers.length) {
            c = 0;
        }
    }
    return setInterval(run, 200);
}

像这样使用:

var timer = setBgPosition();
// ...later, when you're ready to stop...
clearInterval(timer);

尽管如此,我还是想找到一种方法来使setBgPosition事情本身停止,通过检测某些完成条件已得到满足。

@BhawinParkeria:是的,你为什么不呢?句柄与您传入的函数无关setInterval(我会使用clearInterval而不是clearTimeout,但他们会做同样的事情。)
2021-03-22 15:39:11
@philosopher - 你不需要if. :-) 我总是把它放在那里,但0(现在)明确定义为无效的计时器句柄,clearTimeout并且(现在)明确定义为不会在无效的计时器句柄上抛出任何错误或类似内容,因此您可以摆脱它if并保持身体不改变任何东西。(而这些天,我这样做。) Re awaitin run:请注意两件事: 1. 如果您有awaitin run,那么根据定义,它run必须是一个async函数,这意味着它返回一个Promise,这意味着您要返回一个Promise东西([续]中的代码
2021-03-30 15:39:11
如果我使用setInterval(function() { run(argument); }, 200); 我可以使用 cleartimeout
2021-03-31 15:39:11
如果我想在函数运行中传递一个变量怎么样
2021-04-02 15:39:11
@BhawinParkeria:您要么将其包装在这样的函数中;setInterval(function() { run(argument); }, 200);或者你Function#bind像这样使用setInterval(run.bind(null, argument), 200);前者在每次运行时需要查看参数的当前值时很有用,后者在您想要“烘焙” 的当前值argument并继续使用时很有用,即使argument以后发生变化。
2021-04-04 15:39:11

我知道这是一个老问题,无论如何我想发布我的方法。这样你就不必处理 TJ Crowder 解释的 0 把戏。

var keepGoing = true;

function myLoop() {
    // ... Do something ...

    if(keepGoing) {
        setTimeout(myLoop, 1000);
    }
}

function startLoop() {
    keepGoing = true;
    myLoop();
}

function stopLoop() {
    keepGoing = false;
}
这有效,但取消计时器本身更准确,因为您不必等到循环完成,在您的示例中,这可能是一整秒长。
2021-03-17 15:39:11
我知道这是一个古老的答案,但会发生什么,如果你stopLoopstartLoop的内1000超时?你现在不会有两个循环运行,都检查它keepGoing是真的吗?
2021-04-10 15:39:11
没错,@Mirror318。setTimeout返回一个处理程序。应该用 清除该处理程序clearTimeout
2021-04-11 15:39:11

处理超时循环的最简单方法

function myFunc (terminator = false) {
    if(terminator) {
        clearTimeout(timeOutVar);
    } else {
        // do something
        timeOutVar = setTimeout(function(){myFunc();}, 1000);
    }
}   
myFunc(true); //  -> start loop
myFunc(false); //  -> end loop
如果我错了,请纠正我,但逻辑不是颠倒了吗?
2021-03-14 15:39:11

您需要使用一个变量来跟踪“完成度”,然后在循环的每次迭代中对其进行测试。如果 done == true 则返回。

var done = false;

function setBgPosition() {
    if ( done ) return;
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        if ( done ) return;
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length)
        {
            setTimeout(run, 200);
        }else
        {
            setBgPosition();
        }
    }
    setTimeout(run, 200);
}

setBgPosition(); // start the loop

setTimeout( function(){ done = true; }, 5000 ); // external event to stop loop
var myVar = null;

if(myVar)
   clearTimeout(myVar);

myVar = setTimeout(function(){ alert("Hello"); }, 3000);
这可能会回答这个问题。但是,仅代码答案不如记录代码或详细解释为什么此代码是问题解决方案的答案有用。
2021-03-19 15:39:11