简体   繁体   中英

How to stop the setTimeout or setInterval inside loop?

I'd gone through a plenty of posts in SO with the similar queries but unfortunately none of them fit into my requirements or solved my problem.

The problem is When I click play button, I want to go through all the iteration(102) of while with certain delay(for visualisation purpose) until I click the pause button. If the pause button is clicked at iteration 73 execution, I want to stop at the current iteration(73) and save this step. Later, If the play button is pressed, I want to resume from the iteration(73/74) from where I left off. Variable curStp is used to monitor the current steps.

Currently, when the pause button is pressed, the loop is not stopping and it keeps going till it reaches 102.

 let flag = 0; const delay = 300; const totalStps = 102; var curStp = 0; function mouseup() { let i = 0; console.log("Value of flag " + flag); while(i < totalStps - curStp) { const j = i; var timeout = setTimeout(function(){ let stp = curStp; console.log("i " + i + " j " + j + " curStp " + curStp); curStp = stp+1; // this is done by setState. console.log("flag " + flag + " timeout " + timeout); }, delay * i); if (flag === 1) { console.log("break the loop"); clearTimeout(timeout); // This is not stopping this setTimeout break; } i++; } } function pause() { flag = 1; console.log("Value of flag in pause() " + flag + " curStp " + curStp); let stp = curStp; curStp = stp; // this is done by setState. }
 <button onclick="mouseup()">Run Code </button> <button onclick="pause()">Pause Code </button>

I tried the same with setInterval also but no luck. It also runs in a jiffy and hurting my eyes.

 let flag = 0; const delay = 300; const totalStps = 102; var curStp = 0; function mouseup() { let i = 0; console.log("Value of flag " + flag); while(i < totalStps - curStp) { const j = i; (function(i) { var timeout = setInterval(function(){ let stp = curStp; console.log("i " + i + " j " + j + " curStp " + curStp); curStp = stp+1; // this is done by setState. console.log("flag " + flag + " timeout " + timeout); }, delay * i) })(i); if (flag === 1) { console.log("break the loop"); clearInterval(timeout); // This is not stopping this setTimeout break; } i++; } } function pause() { flag = 1; console.log("Value of flag in pause() " + flag + " curStp " + curStp); let stp = curStp; curStp = stp; // this is done by setState. }
 <button onclick="mouseup()">Run Code </button> <button onclick="pause()">Pause Code </button>

Am I missing any thing?

How about you do it this way:

  1. Don't use a while loop because the while loop will call setTimeout many times and then you will have to clear ALL of them to pause. So it is simpler to not use the while loop
  2. When the function is called, let it set a timeout again after it is run.
  3. This means when toRepeat in my example below runs, it will create a timeout to run again so it runs the next step. Then it runs again and calls setTimeout again and so on until curStp is less than totalStps

Here is an example with comments, let me know if anything needs clarification.

let flag = 0;
const delay = 300;
const totalStps = 102;
var curStp = 0;
var timeout = null;

function toRepeat() {
    let stp = curStp;
    console.log("curStp = " + curStp);
    
    curStp = stp+1;   // this is done by setState.
    console.log("flag " + flag + " timeout " + timeout);

    // check for pause
    if(flag === 1) {
      console.log("break the loop");
      console.log('clearing timeout = ', timeout);

      // dont continue because we paused
      return;
    }

    // each timeout will call another timeout again for the next step unless we already finished or we have paused
    // better to have this `curStp < totalStps`
    if(curStp != totalStps) {
      // setup another timeout for next step
      timeout = setTimeout(toRepeat, delay);
    } else {
      // we already finished
    }
}

function mouseup() {
  // need to set the flag back to 0 so pressing "Run Code" doesn't immediately pause again
  flag = 0;

  var timeout = setTimeout(toRepeat, delay);
}

function pause() {
  flag = 1;
  console.log("Value of flag in pause()  " + flag + " curStp " + curStp);
  let stp = curStp;
  curStp = stp;   // this is done by setState.
}

You should have a while loop when you use setInterval . The latter already has an (asynchronous) repeat logic!

Here is what I think you only need:

  • timeout should be a variable that has large enough scope to perform clearInterval on it
  • flag is not needed. Just reset timeout to undefined
  • No i or j are needed
  • No repeated calls of setInterval and no delay * i either. Those are ingredients you would sometimes use for setTimeout , but not setInterval

 const delay = 300; const totalStps = 102; let curStp = 0; let timeout; function mouseup() { if (timeout !== undefined) return; // Don't start when already started // No loop here! timeout = setInterval(function() { curStp++; console.log("Current step " + curStp); if (curStp >= totalStps) { console.log("Finished at " + curStp); clearTimeout(timeout); timeout = undefined; curStp = 0; } }, delay); } function pause() { clearTimeout(timeout); timeout = undefined; console.log("Paused at " + curStp); }
 <button onclick="mouseup()">Run Code</button> <button onclick="pause()">Pause Code</button>

The easiest way I can come up with

 const delay = 200; const totalStps = 102; var curStp = 0; var interval function mouseup() { if(!interval){ interval = setInterval(()=>{ if(curStp == totalStps){ pause() } else { curStp = curStp +1 console.log(curStp) } }, delay) } } function pause() { clearInterval(interval) interval = undefined }
 <button onclick="mouseup()">Run Code</button> <button onclick="pause()">Pause Code</button>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM