Javascript 如何停止setTimeout循环?

Javascript 如何停止setTimeout循环?,javascript,css,extjs,settimeout,Javascript,Css,Extjs,Settimeout,我正在尝试用一个图像精灵构建一个加载指示器,我想出了这个函数 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');

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

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);
}
函数setBgPosition(){
var c=0;
变量数=[0,-120,-240,-360,-480,-600,-720];
函数运行(){
Ext.get('common-spinner').setStyle('background-position',number[c++]+'PX0PX');

if(c
setTimeout
返回一个计时器句柄,您可以使用该句柄通过
cleartimout
停止超时

例如:

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
本身,而是让它将
c
设置回
0
。否则,这将不起作用。还要注意,我使用
0
作为超时未挂起时的句柄值;
0
不是
setTimeout
的有效返回值,因此它会生成一个h安迪旗

这也是我认为您最好使用
setInterval
而不是
setTimeout
setInterval
重复的(少数)地方之一。因此:

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
停止事情本身。

您需要使用一个变量来跟踪“doneness”,然后在循环的每个迭代中测试它。如果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 done=false;
函数setBgPosition(){
如果(完成)返回;
var c=0;
变量数=[0,-120,-240,-360,-480,-600,-720];
函数运行(){
如果(完成)返回;
Ext.get('common-spinner').setStyle('background-position',number[c++]+'PX0PX');

如果(c我不确定,但可能是您想要的:

var c = 0;
function setBgPosition()
{
    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
        {
            Ext.get('common-spinner').setStyle('background-position', numbers[0] + 'px 0px');
        }
    }
    setTimeout(run, 200);
}
setBgPosition();
var c=0;
函数setBgPosition()
{
变量数=[0,-120,-240,-360,-480,-600,-720];
函数运行()
{
Ext.get('common-spinner').setStyle('background-position',number[c++]+'PX0PX');

如果(c我知道这是一个老问题,我想发布我的方法。这样你就不必处理t.J.Crowder解释的0技巧

var keepGoing = true;

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

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

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

function stopLoop() {
    keepGoing = false;
}

由于这是用extjs标记的,因此可能值得一看extjs方法:

这与setInterval的工作原理非常相似,但也考虑了作用域,并允许传递参数:

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 Ext.Function.interval(run,200);
}

var bgPositionTimer = setBgPosition();
一个示例用例是:

Ext.Ajax.request({
    url: 'example.json',

    success: function(response, opts) {
        clearInterval(bgPositionTimer);
    },

    failure: function(response, opts) {
        console.log('server-side failure with status code ' + response.status);
        clearInterval(bgPositionTimer);
    }
});

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

function myFunc (terminator = false) {
    if(terminator) {
        clearTimeout(timeOutVar);
    } else {
        // do something
        timeOutVar = setTimeout(function(){myFunc();}, 1000);
    }
}   
myFunc(true); //  -> start loop
myFunc(false); //  -> end loop
var myVar=null;
if(myVar)
清除超时(myVar);
myVar=setTimeout(函数(){alert(“Hello”);},3000);

如果要从函数内部停止循环,请尝试以下操作:

let timer = setInterval(function(){
  // Have some code to do something

  if(/*someStopCondition*/){ 
    clearInterval(timer)
  }
},1000);


您也可以将其包装到另一个函数中,只需确保您有一个计时器变量并使用clearInterval(timerVariable)停止循环

在顶部答案中,我认为
if(timer)
语句被错误地放在
stop()
函数调用中。它应该放在
run()中
函数调用,如
if(timer)timer=setTimeout(run,200)
。这可以防止以后的
setTimeout
语句在调用
stop()
之后立即运行

编辑2:对于同步函数调用,上面的答案是正确的。如果要进行异步函数调用,请使用我的答案

下面给出了一个我认为正确的方法的示例(如果我错了,请感觉纠正我,因为我还没有测试过这个方法):


编辑1:这已经过测试,并按预期工作。

如果(cno)不使用else,动画只工作一次,是否要在函数中传递变量时停止循环run@BhawinParkeria:您可以将其包装在如下函数中;
setInterval(function(){run(argument);},200)
或者像这样使用
函数#bind
setInterval(run.bind(null,argument),200);
前者在每次运行时需要查看参数的当前值时非常有用,后者在“烘焙”时非常有用
argument
的当前值,即使
argument
以后更改,也要继续使用该值。如果使用
setInterval(function(){run(argument);},200);
我可以使用吗cleartimeout@BhawinParkeria:是的,为什么不呢?句柄与传递到
setInterval
的函数无关。(我会使用
clearInterval
而不是
clearTimeout
,但它们会做同样的事情。)@T.J.Crowder优雅的解决方案,但您能解释一下为什么需要
if(计时器)
停止函数中的语句?为什么不能直接调用
clearTimeout
呢?此外,如果
run
函数在
timer=setTimeout(run,200)之前有
Wait
语句,这是否仍能像预期的那样工作
被调用?我知道这是一个古老的答案,但是如果在
1000
超时时间内
stopLoop
startoop
会发生什么?你现在不会有两个循环运行,都在检查
keepGoing
是否为真?没错,@Mirror318.
setTimeout
返回一个处理程序。该处理程序应该在ith
clearTimeout
。这可以工作,但取消计时器本身更准确,因为您不必等待循环完成,在您的示例中,这可能需要整整一秒钟的时间。这可能会回答这个问题。但是,仅代码的答案不如记录代码的答案有用,也没有详细解释为什么在最上面的答案中,我认为if(timer)语句被错误地放置在stop()函数调用中“不,它在正确的位置。它在那里,这样当你调用stop时,如果计时器正在运行,它就会停止计时器。正如我所说,你不必在调用
cleartimout
(这些天我不知道),但这并没有错。@t.J.Crowder谢谢
let timer = setInterval(function(){
  // Have some code to do something

  if(/*someStopCondition*/){ 
    clearInterval(timer)
  }
},1000);

const runSetTimeoutsAtIntervals = () => {
    const timeout = 1000 // setTimeout interval
    let runFutureSetTimeouts // Flag that is set based on which cycle continues or ends

    const runTimeout = async() => {
        await asyncCall() // Now even if stopRunSetTimeoutsAtIntervals() is called while this is running, the cycle will stop
        if (runFutureSetTimeouts) runFutureSetTimeouts = setTimeout(runTimeout, timeout)
    }

    const stopRunSetTimeoutsAtIntervals = () => {
        clearTimeout(runFutureSetTimeouts)
        runFutureSetTimeouts = false
    }

    runFutureSetTimeouts = setTimeout(runTimeout, timeout) // Set flag to true and start the cycle
    return stopRunSetTimeoutsAtIntervals
}

// You would use the above function like follows.
const stopRunSetTimeoutsAtIntervals = runSetTimeoutsAtIntervals() // Start cycle
stopRunSetTimeoutsAtIntervals() // Stop cycle