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(csetTimeout
返回一个计时器句柄,您可以使用该句柄通过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
返回一个处理程序。该处理程序应该在ithclearTimeout
。这可以工作,但取消计时器本身更准确,因为您不必等待循环完成,在您的示例中,这可能需要整整一秒钟的时间。这可能会回答这个问题。但是,仅代码的答案不如记录代码的答案有用,也没有详细解释为什么在最上面的答案中,我认为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