Why is my setTimeout function not waiting for the time specified? - javascript

I have a for loop and I want to print its i'th value after a delay but with setTimeout() function, it waits for specified time but then every value of i prints without any delay. Is this because setTimeout() is an Async function and by the time it completes its first countdown, the time for all other values is also over.
for(let i=0;i<10;i++){
setTimeout(()=>{
console.log(i);
},10);
}
OUTPUT:
(10ms Gap) 1-2-3-4-5
OUTPUT REQUIRED: 1 - 10ms Gap - 2 -10ms Gap--... So on. Kindly provide the reason for solution.

You are repeatedly calling setTimeout() in your loop, if you just want to delay your loop, you could try something like this.
loopWithDelay();
async function loopWithDelay() {
for(let i = 0; i < 10; i++){
console.log(i)
await delay(100);
}
}
var timer;
function delay(ms) {
return new Promise((x) => {
timer = setTimeout(x, ms);
});
}

You are correct that the setTimeout is asynchronous, therefore every console.log(i) is set to run at basically the same time. I find it easier to use setInterval in your scenario:
let i = 0;
let myInterval = setInterval(() => {
console.log(i);
i++;
if (i === 10) {
clearInterval(myInterval);
}
}, 10);

You can modify the timer in the loop for every item.
for(let i=0;i<10;i++){
setTimeout(()=>{
console.log(i);
},10*(i+1));
}
This ensures proper gap between every item.
I hope it helps.

Yes, setTimeout() is an async function and all the countdowns start at almost the exact time because there is no waiting time between succesive setTimeout() calls.
What you can do in order to get the expected behaviour is put the for in a function and call that function back from setTimeout() when the countdown runs out:
function f(i) {
if(i < 10) {
setTimeout(()=> {
console.log(i);
f(i+1);
}, 10);
}
}
f(0);

Related

For Loop SetTimeout Works Only 1 Time

I have a button with click function below. It has 3 nested for loop, and 1 setTimeout function.
The below loops are looping 5 times. I want below code to work(5x5) total 25 seconds of execution time, and each 5 seconds console output should be "Waited" printed.
However below code works only 5 seconds, and immediately prints "5 hello". Without changing my for loop structure, how can I make it work as I want?
jQuery("#btn_trendyolStocksSYNC").click(function() {
for(var product in all){
var colors = all[product];
for(var singleColor in colors[0]){
var size = colors[0][singleColor];
for(var index in size){
var singleSize = size[index];
setTimeout(function (){
console.log('Waited');
}, 5000);
}
}
}
});
Edit: I don't use the for loop with indexes, so solutions for number indexed for loops are not working for me.
You could try by adding await and a Promise:
jQuery("#btn_trendyolStocksSYNC").click(async function() {
for(var product in all){
var colors = all[product];
for(var singleColor in colors[0]){
var size = colors[0][singleColor];
for(var index in size){
var singleSize = size[index];
await new Promise(resolve => setTimeout(function (){
console.log('Waited');
resolve();
}, 5000));
}
}
}
});
What this does is simply tell your loop to stop and only continue once the Promise object calls its resolve parameter function. That way your delay should simply happen before the next iteration. This is the important code:
await new Promise(resolve => setTimeout(function (){
console.log('Waited');
resolve();
}, 5000));
It simply creates a Promise that we will resolve once the timeout has let 5000 milliseconds pass. Then we tell our loop to simply await that completion before continuing to the next item.
Note You also need to add async to your handler function, so javascript knows that this function can wait and take as long as it needs to.
The setTimeout(); function is asynchronous, meaning that your script will not wait for it to finish before moving on. That's why it has a callback.
Try something like this: (not the best method)
//delayed loop
var i = 1;
function loop() {
//wait 5 secs
setTimeout(function() {
console.log(i);
if(i>5) {
//cancel
return;
}
loop();
i++;
return;
}, 1000);
if(i>5) {
//cancel function
return;
}
}
//do the loop
loop();
Like what somethinghere said, you could put the setTimeout in the if statement.
Of course to do something after the loop ends you need a callback function.
you can use setInterval and clearInterval.
var n=0;
var a = setInterval(()=>{
console.log("Waited");
n++; if(n==5){clearInterval(a);}
},5000);

Angular 4 setTimeout() with variable delay and wait

I have a list of events with timestamp.
What I want is to display the events based on the timestamp:
To add a delay:
delay = timestamp(t+1) - timstamp(t)
I know this doesn't work well with setTimeout, but there is an workaround, if the timeout is constant, in my case is not.
Is it possible to make the next setTimeout() wait for the previous one? To be specific, if the first setTimeout() has a 5 second delay and the second one has 3 seconds, the second one will appear first. I want them to be in the same order but execute one after the other.
This example works for a constant delay, but I want to calculate the delay based on the information I take iterating the list.
for (i = 1; i <= 5; ++i) {
setDelay(i);
}
function setDelay(i) {
setTimeout(function(){
console.log(i);
}, 1000);
}
You can use IIFE (Immediately Invoked Function Expression) and function recursion instead. Like this:
let i = 0;
(function repeat(){
if (++i > 5) return;
setTimeout(function(){
console.log("Iteration: " + i);
repeat();
}, 5000);
})();
Live fiddle here.
When using the latest Typescript or ES code, we can use aync/await for this.
let timestampDiffs = [3, 2, 4];
(async () => {
for (let item of timestampDiffs) {
await timeout(item * 1000);
console.log('waited: ' + item);
}
})();
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
We need to wrap the for loop in an async immediately invoked function because to support await.
We also do need a timeout function that returns a promise once the timeout is complete.
After that, we wait for the timeout to complete before continuing with the loop.
Don't call it within a loop, as it won't wait for the setTimeout to complete.
You can instead pass a list of times that you want to wait, and iterate them recursively:
let waits = [5000, 3000, 1000];
function setDelay(times) {
if (times.length > 0) {
// Remove the first time from the array
let wait = times.shift();
console.log("Waiting", wait);
// Wait for the given amount of time
setTimeout(() => {
console.log("Waited ", wait);
// Call the setDelay function again with the remaining times
setDelay(times);
}, wait);
}
}
setDelay(waits);
You can set time out period using i value dynamically. Like
for (i = 1; i <= 5; ++i) {
setDelay(i);
}
function setDelay(i) {
setTimeout(function(){
console.log(i);
}, i*1000);
}
You can think of something like that:
setDelay(1,5);
function setDelay(i, max) {
setTimeout(function(){
console.log(i);
if(i < max){
i++;
setDelay(i, max);
}
}, 1000);
}
The idea is to set the next setTimeout(.. in a timeout.
Of course you can modify it to have different long timeouts as well.
Hope i can help :)

setTimeout function in JavaScript doesn't output number at correct time intervals

I'm not understanding why this function outputs 1-5 in successive order as intended, but at 1 second intervals rather than 1,2,3, etc. seconds. I'm unfamiliar with the setTimeout function and I understand that something is going on with the arguments to the function here that I'm not seeing.
var counter = function() {
for (var i = 1; i <= 5; i++) {
(function(x){
setTimeout(function timer() {
console.log(x);
}, (x * 1000));
})(i);
}
};
You can avoid the for loop by calling it recursively, just pass the start and stop index.
var counter = function (x, y) {
setTimeout(function timer() {
console.log(x);
if (x != y) counter((x + 1),y);
}, (x * 1000));
};
counter(1, 5);
Fiddle demo
Because you are immediately placing all your calls to setTimeout. So, during the same event, JS receives the instruction to call timer: after 1000ms, after 2000ms, after 3000ms, after 4000ms and after 5000ms. Which is exactly what it does, so timer is called every 1 second.
If you wish to progressively increase the interval, your loop should be rewritten as a recursive loop, in which the next call to setTimeout is performed by timer.
As #putvande said you are setting all 5 timeouts at the same time with different intervals.
var counter = function(){
for (var i=1; i<=5; i++) {
console.log('setting timer for ' + i);
(function(x){
setTimeout( function timer(){
console.log(x);
}, (x*1000) );
})(i);
}
};
counter();
An extra log statement show this. Your timers are firing at the right interval, 1st one at 1 second, 2nd one at 2 seconds, etc.

jQuery Promise with setTimeout

I need one setInterval to start after another setInterval ends. Is there a way to do this with promises?
Ideally, I would like the code to look something like this:
for (i=0; i<5; i++){
setInterval(fun_1, 1000)
//wait until this is done
}
The setInterval calls the provided function after given interval of time until you clear its object. So you do not need a loop for this. You can use a counter to terminate it after counter reaches desired value.
Live Demo.
var myInter;
i = 1;
function fun_1()
{
// some code
if(i++==5)
clearInterval(myInter);
}
myInter = setInterval(fun_1, 1000);
Do you mean that you would like the second interval to begin the countdown after the previous interval is done? In that case, you would say
window.setTimeout(fun_1, 1000);
function fun_1
{
window.setTimeout(fun_2, 1000);
}
This starts the countdown for the second timeout after the first one has completed.
You should call the next interval after the first one completes
var cnt = 0;
function executeNextStep(){
fun_1();
if (cnt<5) {
window.setTimeout(executeNextStep,1000);
}
cnt++;
}
executeNextStep(); //execute this right away
//window.setTimeout(executeNextStep,1000); use this if you want it to be delayed
if you need to execute different functions:
function fun_1() {
console.log(1);
}
function fun_2() {
console.log(2);
}
function fun_3() {
console.log(3);
}
var fnc_stack = [fun_1, fun_2, fun_3];
var cnt = 0;
function executeNextStep(){
fnc_stack[cnt]();
cnt++;
if (cnt<fnc_stack.length) {
window.setTimeout(executeNextStep,1000);
}
}
executeNextStep();

Why isn't clearInterval working in this code?

There is a function which sets an interval using setInterval(), but even after calling clearInterval(), I can see in the console that the else condition is still running. How can I clear that interval properly?
function increase(old, step, neu) {
var i = 0;
var delay2;
function countUp() {
if (i < 5) {
old += step;
// console.log("increase")
$("#total-price-value").text(old + " dollors");
$("#total-price-value").digits();
i++;
delay2 = setInterval(countUp, 80);
} else {
clearInterval(delay2);
console.log(delay2);
}
}
countUp();
}​
It looks like you're a little confused about the difference between timeouts and intervals. Timeouts fire only once; intervals fire many times. If you're using an interval, you probably only want to set it once (you're setting it every time). If you're using a timeout, you probably want to set it every time (like you're doing).
In order to fix the problem, you'll either want to switch to timeouts (probably the easiest; just a search/replace) or only set the interval once.
For example, here is how one might use setTimeout to count up to five:
var count = 0;
function timeoutFired() {
count++;
if(count < 5) {
setTimeout(timeoutFired, 1000);
}
}
setTimeout(timeoutFired, 1000);
Using timeouts, we don't need to clear to stop it from counting; simply not setting a timeout will prevent it from running again.
Here is how one might use setInterval:
var count = 0;
function intervalFired() {
count++;
if(count >= 5) {
clearInterval(interval);
}
}
var interval = setInterval(intervalFired, 1000);
If you want some code running periodically using intervals to stop, you must call clearInterval. Note that we only call setInterval once, versus setTimeout every time we didn't want it to continue.
Apparently, you have mistaken setInterval for setTimeout. setInterval runs the enclosed function every n milliseconds while setTimeout executes only once after n milliseconds.
I suppose you wanted to "tick until 5" so here's a sample:
function increase(old, step, neu) {
var i = 0;
interval = setInterval(function() {
if (i < 5) {
//do something at this "tick"
console.log(i);
i++;
} else {
//else, stop
clearInterval(interval);
}
},80);
}
increase();

Categories