Search code examples
javascriptsettimeoutsetinterval

Javascript setInterval and setTimeout giving unexpected results


I have a setInterval with an interval of 4 seconds , which is calling a function fun1. Now for the first Hi to print it is taking 16 seconds which is understandable but now after every 4 seconds I am seeing a "Hi".

Why there is a no delay of 16 seconds now? I am seeing that 12 second delay only once

function fun1() {
  setTimeout(() => {
    console.log("Hi");
  }, 12000);
}

setInterval(async() => {
  await fun1();
}, 4000);

I tried incrementing value of p every time , to check if fun1() is running only once but , the value is incrementing every time so why there is no delay now. I expect 16 seconds delay after every "Hi".


Solution

  • What is happening?

    When you start your program, setInterval is set to call fun1() every 4 seconds. However, in fun1(), you have a setTimeout that waits for 12 seconds before printing "Hi". Therefore, for the first "Hi" to appear, it takes 4 seconds (for the first setInterval call) + 12 seconds (setTimeout delay) = 16 seconds.

    After the first call, setInterval continues to call fun1() every 4 seconds. However, each call to fun1() sets up a new setTimeout that will trigger 12 seconds later. This means that after the initial delay, there will be overlapping setTimeout calls.

    • At 8 seconds (from the start), the second call to fun1() happens, setting up a setTimeout to print "Hi" at 20 seconds.

    • At 12 seconds (from the start), the third call to fun1() happens, setting up a setTimeout to print "Hi" at 24 seconds.

    • And so on.

    So, after the first "Hi" at 16 seconds, every subsequent "Hi" comes from a setTimeout that was set up in a previous cycle of setInterval. This results in a new "Hi" appearing every 4 seconds, which is the interval of your setInterval, but offset by the initial 12-second delay from the setTimeout.

    How to fix it?

    If you want a 16-second delay between each "Hi", you would need to ensure that fun1() does not get called again until after its setTimeout has been completed. This could be achieved by using setTimeout instead of setInterval and recursively calling fun1() at the end of the setTimeout:

    function fun1() {
      setTimeout(() => {
        console.log("Hi");
        fun1(); // Recursively call fun1
      }, 16000);
    }
    
    fun1(); // Initial call to start the cycle