How to stop a setTimeout loop?
setTimeout
returns a timer handle, which you can use to stop the timeout with clearTimeout
.
So for instance:
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;
}
}
So you'd use that as:
var stop = setBgPosition();
// ...later, when you're ready to stop...
stop();
Note that rather than having setBgPosition
call itself again, I've just had it set c
back to 0
. Otherwise, this wouldn't work. Also note that I've used 0
as a handle value for when the timeout isn't pending; 0
isn't a valid return value from setTimeout
so it makes a handy flag.
This is also one of the (few) places I think you'd be better off with setInterval
rather than setTimeout
. setInterval
repeats. So:
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);
}
Used like this:
var timer = setBgPosition();
// ...later, when you're ready to stop...
clearInterval(timer);
All of the above notwithstanding, I'd want to find a way to make setBgPosition
stop things itself, by detecting that some completion condition has been satisfied.
How to stop setTimeout loop if condition is met
You can't break the loop like that. Your loop creates all these setTimeout
immediately. Your condition will just never trigger. What you'll need to do is clear out all those setTimeout
. You can push them into an array.
let animationTimeouts;
function startScreensaver() {
animationTimeouts = [];
screensaverActive = true;
screenSaver.classList.add("is--active");
for (let index = 0; index < stars.length; index++) {
if (screensaverActive) {
animationTimeouts.push(setTimeout(function () {
stars[index].classList.add("is--visible");
}, 2000 * index));
} else {
break;
}
}
}
Then clear them out on stopScreensaver
function stopScreensaver() {
screensaverActive = false;
if(animationTimeouts) animationTimeouts.forEach(clearTimeout);
stars.forEach((star) => {
star.classList.remove("is--visible");
});
screenSaver.classList.remove("is--active");
}
You might also want to reconsider moving your CSS transition to .star.is--visible
Stop loop function setTimeout
You can clear the timeout and also set a flag that will alert the callback in $.get
that it shouldn't call timeOut()
when it returns:
let i = 0;let sett;let active = true // should the loop continue?function timeOut(counter) { if (counter < 10){ sett = setTimeout(function () { $.get("./test3.php", {data_id: counter}, (data) => { console.log(data); i++; if (active) timeOut(i); // only if active }); }, 1000); } else { alert("Done!"); }}timeOut(i);function clickStop() { active = false // stop loop clearTimeout(sett); // and clear current timeout}
Breaking out of setTimeout loop
Instead of setting all those timers, create one continuous timer with setInterval
:
var counter = 0;
var timer = setInterval(function () {
console.log("turn no. " + counter);
if (table.game.playerWon) {
console.log('Player won');
}
if (counter >= 75 || table.game.playerWon) {
clearInterval(timer);
}
counter++;
}, 100);
If your turns should take 500ms, change that last 100
to 500
.
Stop setTimeout loop, activated after click on button
This is exactly what you want (you can remove the console stmt after testing),
<script>
document.getElementById("addurls").onclick = function () {
var allurls = document.getElementById("allurls"); //$('#allurls').val().split('\n');
var urls = allurls.value.split('\n');
var el = document.getElementById("indexer");
var index = 0;
timer = setTimeout(function rotate() {
if (index === urls.length) {
clearTimeout(timer);
return true;
}
el.src = urls[index];
console.log("TEST: ", index);
index++;
timer = setTimeout(rotate, 2000);
}, 0);
};
</script>
Immediately stop a setTimeout loop without finishing current cycle
Your problem is in the flit()
function - you need to assign references to the setTimeout
calls so you can call clearTimeout
on them. Right now, you're stopping flit()
from being called in the select()
method, but the two timers are still queued to execute in the future.
How to stop the setTimeout or setInterval inside loop?
How about you do it this way:
- 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
- When the function is called, let it set a timeout again after it is run.
- 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 callssetTimeout
again and so on untilcurStp
is less thantotalStps
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.
}
How to terminate endless while loop via setTimeout in Javascript
JavaScript runs a single event loop. It won't stop in the middle of a function to see if there are any events (such as clicks or timeouts) that would trigger a different function.
In short: It won't run the timed function until the while loop has finished.
To do this sort of thing, you'd normally have an event driven iterator.
var i = 0, s = false;
setTimeout(function() { s = true; console.log("Timeuot!!!"); console.log("s value is " + s);}, 1000);
next();
function next() { if (s) { return done(); } console.log({ s, i }); i++; setTimeout(next, 0);}
function done() { console.log("iterations: " + i);}
Related Topics
Changing a CSS Rule-Set from JavaScript
How to Make a Div Stick to the Top of the Screen Once It's Been Scrolled To
How to Change the Background Color With JavaScript
How to Simulate a Mouseover in Pure JavaScript That Activates the CSS ":Hover"
How to Add CSS With JavaScript
Jquery CSS Plugin That Returns Computed Style of Element to Pseudo Clone That Element
Restart Animation in Css3: Any Better Way Than Removing the Element
Prevent Body from Scrolling When a Modal Is Opened
Detecting the System Dpi/Ppi from Js/Css
How to Transform Black into Any Given Color Using Only CSS Filters
Instead of Using Prefixes I Want to Ask Site Visitors to Upgrade Their Browser
How to Disable a Browser or Element Scrollbar, But Still Allow Scrolling With Wheel or Arrow Keys
How to Get the Background Color Code of an Element in Hex
Removing or Replacing a Stylesheet (A ≪Link≫) With JavaScript/Jquery
How to Print a Number With Commas as Thousands Separators in JavaScript