The setTimeout() function is non-blocking and will return immediately. Therefore your loop will iterate very quickly and it will initiate 3-second timeout triggers one after the other in quick succession. That is why your first alerts pops up after 3 seconds, and all the rest follow in succession without any delay.
You may want to use something like this instead:
var i = 1; // set your counter to 1
function myLoop() { // create a loop function
setTimeout(function() { // call a 3s setTimeout when the loop is called
console.log('hello'); // your code here
i++; // increment the counter
if (i < 10) { // if the counter < 10, call the loop function
myLoop(); // .. again which will trigger another
} // .. setTimeout()
}, 3000)
}
myLoop(); // start the loop
You could also neaten it up, by using a self invoking function, passing the number of iterations as an argument:
(function myLoop(i) {
setTimeout(function() {
console.log('hello'); // your code here
if (--i) myLoop(i); // decrement i and call myLoop again if i > 0
}, 3000)
})(10); // pass the number of iterations as an argument
Answer from Daniel Vassallo on Stack OverflowThe setTimeout() function is non-blocking and will return immediately. Therefore your loop will iterate very quickly and it will initiate 3-second timeout triggers one after the other in quick succession. That is why your first alerts pops up after 3 seconds, and all the rest follow in succession without any delay.
You may want to use something like this instead:
var i = 1; // set your counter to 1
function myLoop() { // create a loop function
setTimeout(function() { // call a 3s setTimeout when the loop is called
console.log('hello'); // your code here
i++; // increment the counter
if (i < 10) { // if the counter < 10, call the loop function
myLoop(); // .. again which will trigger another
} // .. setTimeout()
}, 3000)
}
myLoop(); // start the loop
You could also neaten it up, by using a self invoking function, passing the number of iterations as an argument:
(function myLoop(i) {
setTimeout(function() {
console.log('hello'); // your code here
if (--i) myLoop(i); // decrement i and call myLoop again if i > 0
}, 3000)
})(10); // pass the number of iterations as an argument
Since ES7 theres a better way to await a loop:
// Returns a Promise that resolves after "ms" Milliseconds
const timer = ms => new Promise(res => setTimeout(res, ms))
async function load () { // We need to wrap the loop into an async function for this to work
for (var i = 0; i < 3; i++) {
console.log(i);
await timer(3000); // then the created Promise can be awaited
}
}
load();
When the engine reaches the await part, it sets a timeout and halts the execution of the async function. Then when the timeout completes, execution continues at that point. That's quite useful as you can delay (1) nested loops, (2) conditionally, (3) nested functions:
async function task(i) { // 3
await timer(1000);
console.log(`Task ${i} done!`);
}
async function main() {
for(let i = 0; i < 100; i+= 10) {
for(let j = 0; j < 10; j++) { // 1
if(j % 2) { // 2
await task(i + j);
}
}
}
}
main();
function timer(ms) { return new Promise(res => setTimeout(res, ms)); }
Reference on MDN
While ES7 is now supported by NodeJS and modern browsers, you might want to transpile it with BabelJS so that it runs everywhere.
Adding a delay to each iteration of loop?
Javascript delay with while loop - Stack Overflow
How to pause for 1 second in between the iterations of my loop
Create a pause inside a while loop in Javascript - Stack Overflow
Videos
Hi everyone,
I'm desperate and in need of some guidance :P
I'm trying to create a classic algorithm visualiser kind of thing (in React), and am now implementing the first of the list, bubblesort.
The idea is to add a small delay after each sorting action, so that there's enough time for the user to see the animation unfolding.
const bubbleSort = (data) => { //data is array of nums
const newData = [...data]
let len = data.length
let swapped
do {
swapped = false
for (let i = 0; i < len; i++) {
setTimeout(() => { //delaying action
if (newData[i] > newData[i + 1]) {
let tmp = newData[i]
newData[i] = newData[i + 1]
newData[i + 1] = tmp
console.log(newData)
swapped = true //! eslint unsafe reference
}
}, i * 1000) // add enough time for each action to be done in succession
}
} while (swapped)
console.log("done?") //!Triggers immediately - because of asynchronicity
return newData
}
export default bubbleSortThe main issue is that it stops after sorting just a single value. However, commenting out the setTimeout wrapper makes the sorting happen fully and perfectly. So I'm guessing something is going wrong with the asynchronicity?
Another issue that I'm getting is an eslint no-loop-func warning: "Function declared in a loop contains unsafe references to variable swap". I read through the eslint docs and understand that it's being flagged because of possible scope complications, but I have no idea how to fix it in this implementation.
I looked through this and this, but am having a hard time relating and applying what they say to my case.
I hope someone can point me in the right direction with this (it's been a long day trying to figure this out). All I need is to delay each iteration.
Thanks in advance!
This works:
var on = true,
sw = document.getElementById("switch"),
stop, y = 0,
dir, to;
function animate() {
sw.style.backgroundPosition = y + 'px 0px';
y += dir;
if (y != stop) {
to = setTimeout(animate,25);
}
}
function toggle() {
if (to) {
clearTimeout(to);
}
if (on) {
dir = -1;
stop = -38;
}
else {
dir = 1;
stop = 2;
}
to = setTimeout(animate, 25);
on = !on;
}
DEMO
Don't know if it is the best way though.
Note: You either have to run the code in the body.onload event handler or put it at the bottom of the page.
You can also try to play with the step size and the timeout time.... there was something else I wanted to say, but I forgot ;)
Another note: You should always use expressive variable names. E.g. It was not clear that x is used as a boolean indicator (at least not if you only have a quick lock at it).
The setTimeout function doesn't pause, it just arranges to execute the function (its first argument) after the specified delay and then immediately returns. So, launching a whole bunch of timeouts isn't that useful. You want the setTimeout callback to call setTimeout to start another timer. And you can use a function rather than a string as the first argument to setTimeout.
setTimeout does not pause; it asks Javascript to run some other code later.
Googling for "setTimeout loop" tells you exactly what you need to know. If you look around a little bit, it even mentions setInterval. The difference: using setTimeout to loop will wait 3 seconds in between loops, whereas setInterval will make it take 3 seconds total for the loop (including however much time the animation takes, as long as it's less than 3 seconds :) ). Also, setInterval constructs an infinite loop that you'll have to break out of after the desired number of times; setTimeout requires you to construct the loop yourself.
i = 0;
// setTimeout approach
function animation_loop() {
someAnimation();
setTimeout(function() {
i++;
if (i < n) {
animation_loop();
}
}, 3000);
};
animation_loop();
// setInterval approach
i = 0;
someAnimation();
iid = setInterval(function() {
i++;
if (i < n) {
someAnimation();
} else {
clearInterval(iid);
}
}, 3000);
setTimeout is a little trickier than that because it doesn't block (i.e. it doesn't finish waiting on the timeout before continuing with the program).
What you want is closer to this:
var i = 0;
function nextFrame() {
if(i < n) {
someanimation();
i++;
// Continue the loop in 3s
setTimeout(nextFrame, 3000);
}
}
// Start the loop
setTimeout(nextFrame, 0);
It may also be worth your while to read up on setInterval as a possible alternative.
You'll have to go that way:
function jsHello(i) {
if (i < 0) return;
setTimeout(function () {
alert("Hello " + i);
jsHello(--i);
}, 2000);
}
jsHello(5);
or
function jsHello(i) {
alert("Hello " + i);
if (--i > -1) {
setTimeout(function () { jsHello(i); }, 2000);
}
}
jsHello(5);
Javascript doesn't have a wait command. The way to get this behavior is using setTimeout:
for (var i=0; i<8; i++){
do_something(i);
}
function do_something(j) {
setTimeout(function() {
tasks to do;
}, 2000 * j);
}
Every time the function do_something() is called, it executes "tasks to do" scheduled by 2000*i milliseconds.