Henry
Henry

Reputation: 118

Multiple SetTimeouts execute together

I recently try to learn Webdesign and wanted to do a simple fadeout of an image with JavaScript. I Know there is an easier way with jQuery and after some time with this problem i used that way, but i stumbles across it and want to unterstand why this happens.

To break down the process lets say I have an image and want it to reduce its opacity every 0.1 seconds. Therefore I used a for loop and called a fade function with SetTimeout(fade,100). But every of the 10 loops are executed at the same time. I tried it even more simple with

setTimeout(fade,100);
setTimeout(fade,100); ....

Even then all 10 instances of the funtion get executed at once. So for future projects: why is that and is there a possible workaround?

Thank you very much

Upvotes: 0

Views: 1329

Answers (4)

Liang
Liang

Reputation: 515

If you want to use setTimeout to change opacity for every 100 ms, you can try this

setTimeout(fade,100);
setTimeout(fade,200);
setTimeout(fade,300);
...

or set a timing variable in loop

for(let timing=100,timeing<1000,timing+=100) setTimeout(fade,timing);

The 10 setTimeout function almost start at same time and trigger at every 100ms till 1000ms. Because it is asynchronous function, it doesn't wait for previous command to finish.

Upvotes: 0

Vivek Athalye
Vivek Athalye

Reputation: 2979

There are multiple ways to achieve it. As others have suggested you can use setInterval or use setTimeout to call recursively. If you must use for loop for some reason, that is also possible.

The basic idea is your call to second setTimeout must be given only after the first execution of fade function or otherwise increase the timeout period between successive calls to setTimeout.

//\//\//\// method 1
function fadeRecur() {
  var d1 = document.querySelector( ".d1" );
  if(d1.style.opacity == '') d1.style.opacity = 1;
  //console.log(d1.style.opacity);
  if(d1.style.opacity > 0) {
    d1.style.opacity -= 0.1;
    setTimeout(fadeRecur, 100);
  }
}
setTimeout(fadeRecur, 100);

//\//\//\// method 2
var fsi;

function fadeInter() {
  var d2 = document.querySelector( ".d2" );
  if(d2.style.opacity == '') d2.style.opacity = 1;
  // console.log(d2.style.opacity);
  if(d2.style.opacity > 0) {
    d2.style.opacity -= 0.1;
  } else {
    clearInterval(fsi);
  }
}
fsi = setInterval(fadeInter, 100);


//\//\//\// method 3
function fadeLoop() {
  var d3 = document.querySelector( ".d3" );
  if(d3.style.opacity == '') d3.style.opacity = 1;
  //console.log(d3.style.opacity);
  if(d3.style.opacity > 0) {
    d3.style.opacity -= 0.1;
  }
}
for(var i=1; i<=10; i++) {
  setTimeout(fadeLoop, i*100);
}
.d1 {
  background-color: rgba(255, 0, 0, 0.5);
}
.d2 {
  background-color: rgba(0, 255, 0, 0.5);
}
.d3 {
  background-color: rgba(0, 0, 255, 0.5);
}
<div class='d1'>recursive setTimeout</div>
<div class='d2'>single setInterval</div>
<div class='d3'>setTimeout in for loop</div>

Upvotes: 0

Ankit Rastogi
Ankit Rastogi

Reputation: 675

The answer is the event loop. To thoroughly understand this behaviour you have to understand all stages of event loop and especially how setTimeout and setInterval is handled

MDN article on event loop MDN event loop

Rising stack article will help you in getting a clear understanding of event loop along with micro and macro task

rising stack event loop explained

In nutshell all setTimeout gets processed in same tick of the loop.

Also for your case setInterval is much better

Upvotes: 0

Faheem
Faheem

Reputation: 1166

You should use setInterval.

setInterval(fade,100);

setInterval is for a repetitive task. It will keep running. Makes sure you clear interval once you are done to prevent memory leakage.

You are using a for loop, which is not the correct way.

Assume at the current instant the time is: 0

You ran a for loop and created 5 setTimeouts. It takes some time to create this but you can't notice it.

So, each setTimeout should execute after 100 ms.

But they are created at:

 1. 0.000000001
 2. 0.000000002
 3. 0.000000003
 4. 0.000000004
 5. 0.000000005

And they will call the callback after:

 1. 100.000000001
 2. 100.000000002
 3. 100.000000003
 4. 100.000000004
 5. 100.000000005

(Just for demonstration)

So, you are not going to notice them and these (setTimeout and setInterval) are not absolute. They make take longer.

Hope it helps. :D

Upvotes: 2

Related Questions