我正在尝试用图像精灵构建一个加载指示器,我想出了这个函数
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();在其他内部保持这个循环运行所以现在我的问题是如何在我想要[加载完成]后停止这个循环?
答案 0 :(得分:82)
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
再次召唤自己,而是将c
设置回0
。否则,这不会起作用。另请注意,我已将0
用作超时暂停时的句柄值; 0
不是来自setTimeout
的有效返回值,因此它会生成一个方便的标记。
这也是我认为你用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
停止本身的方法。
答案 1 :(得分:10)
我知道这是一个老问题,无论如何我想发布我的方法。这样你就不必处理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;
}
答案 2 :(得分:2)
您需要使用变量来跟踪“完成度”,然后在循环的每次迭代中对其进行测试。如果完成== 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
答案 3 :(得分:2)
以最简单的方式处理超时循环
function myFunc (terminator = false) {
if(terminator) {
clearTimeout(timeOutVar);
} else {
// do something
timeOutVar = setTimeout(function(){myFunc();}, 1000);
}
}
myFunc(true); // -> start loop
myFunc(false); // -> end loop
答案 4 :(得分:2)
var myVar = null;
if(myVar)
clearTimeout(myVar);
myVar = setTimeout(function(){ alert("Hello"); }, 3000);
答案 5 :(得分:1)
如果要从函数内部停止循环,请尝试以下操作:
let timer = setInterval(function(){
// Have some code to do something
if(/*someStopCondition*/){
clearInterval(timer)
}
},1000);
您还可以将其包装在另一个函数中,只需确保具有计时器变量并使用clearInterval(theTimerVariable)即可停止循环
答案 6 :(得分:0)
我不确定,但可能是你想要的:
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();
答案 7 :(得分:0)
在最上面的答案中,我认为if (timer)
语句被错误地放在了stop()
函数调用中。应该将其放在run()
之类的if (timer) timer = setTimeout(run, 200)
函数调用中。这样可以防止在调用setTimeout
之后立即运行将来的stop()
语句。
编辑2: 对于同步函数调用,最佳答案是正确的。如果要进行异步函数调用,请改用我的。
下面给出的示例是我认为正确的方法(如果我做错了,可以纠正我),因为我尚未测试过此方法:
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
编辑1: 这已经过测试,可以按预期工作。