[英]How to stop a setTimeout loop?
我正在嘗試用圖像精靈構建一個加載指示器,我想出了這個功能
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(); 在 else 中保持循環運行,所以現在我的問題是如何在我想要 [加載完成] 時停止這個循環?
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
停止事情本身,通過檢測一些完成條件已經得到滿足。
我知道這是一個老問題,無論如何我想發布我的方法。 這樣你就不必處理 TJ Crowder 解釋的 0 把戲。
var keepGoing = true;
function myLoop() {
// ... Do something ...
if(keepGoing) {
setTimeout(myLoop, 1000);
}
}
function startLoop() {
keepGoing = true;
myLoop();
}
function stopLoop() {
keepGoing = false;
}
處理超時循環的最簡單方法
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)
clearTimeout(myVar);
myVar = setTimeout(function(){ alert("Hello"); }, 3000);
您需要使用一個變量來跟蹤“完成度”,然后在循環的每次迭代中對其進行測試。 如果 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
由於這是用 extjs 標簽標記的,因此可能值得查看 extjs 方法: http : //docs.sencha.com/extjs/6.2.0/classic/Ext.Function.html#method-interval
這很像 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();
當你想停止時,你可以使用clearInterval
來停止它
clearInterval(bgPositionTimer);
一個示例用例是:
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);
}
});
如果您想從函數內部停止循環,請嘗試以下操作:
let timer = setInterval(function(){
// Have some code to do something
if(/*someStopCondition*/){
clearInterval(timer)
}
},1000);
您也可以將其包裝在另一個函數中,只需確保您有一個計時器變量並使用 clearInterval(theTimerVariable) 來停止循環
在最佳答案中,我認為if (timer)
語句被錯誤地放置在stop()
函數調用中。 它應該像if (timer) timer = setTimeout(run, 200)
一樣放在run()
函數調用中。 這可以防止在調用stop()
之后立即運行setTimeout
語句。
編輯 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:這已經過測試並且按預期工作。
當任務完成並且您可以顯示任務(在您的情況下為圖像)時,下次刷新時不要發送 javascript。 如果您的服務器使用 PHP。
<?php if (!$taskCompleted) { ?>
<script language="javascript">
setTimeout(function(){
window.location.reload(1);
}, 5000);
</script>
<?php } ?>
我不確定,但可能是你想要的:
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();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.