Timers: setTimeout and setInterval

Learn how to delay or repeat tasks in JavaScript using setTimeout and setInterval, with common mistakes and best practices.

Loading...
Timers: setTimeout and setInterval

When you want to delay a task or run something again and again after a time gap, JavaScript has two timer functions just for that:

  • setTimeout: Runs a function once after a delay.
  • setInterval: Runs a function again and again with a fixed time gap.

Let’s understand each one of them.

setTimeout

setTimeout runs a function once after a delay.

JavaScript is non-blocking and asynchronous. That means, it doesn’t block your code and continues running the rest and comes back later after the delay to run the code inside the setTimeout.

Syntax:

setTimeout(callback, delayInMs, ...args);

Here,

  • callback: Function to run
  • delayInMs: Time in milliseconds (1000ms = 1s)
  • ...args: Optional arguments passed to the callback

Example:

console.log("Before!");
 
setTimeout(() => {
  console.log("Runs after 2 seconds!");
}, 2000);
 
console.log("After!");
 
// Output:
 
// Before!
// After!
// Runs after 2 seconds!

Here,

  • console.log("Before!") runs immediately.
  • setTimeout(() => { ... }, 2000):
    • JavaScript sets a timer for 2000 milliseconds (2 seconds).
    • It schedules the function inside to run later, after 2 seconds.
    • But it doesn't wait and continues running the rest of the code.
  • console.log("After!") runs right after the timeout is scheduled.
  • After 2 seconds, the function inside setTimeout finally runs and Runs after 2 seconds! gets printed to the console.
  • So the final output is:
    • Before!
    • After!
    • Runs after 2 seconds!

Let's take another example.

function greet(name) {
  console.log("Hello", name);
}
 
setTimeout(greet, 1000, "Shefali"); // Output: Hello Shefali (after 1 sec)

Here,

  • function greet(name) {...} is a function and it takes a name and logs "Hello", name to the console.
  • setTimeout(greet, 1000, "Shefali");
    • greet: function to run
    • 1000: delay in milliseconds (1 second)
    • "Shefali": argument passed to greet
  • After 1 second, JavaScript automatically calls: greet("Shefali");
  • So the output is Hello Shefali (after 1 second).

setTimeout with 0 delay

Even if you set the delay to 0, the callback still goes to the event queue and runs after the current code finishes.

For example:

console.log("First!");
 
setTimeout(() => {
  console.log("Third!");
}, 0);
 
console.log("Second!");
 
// Output:
 
// First!
// Second!
// Third!

Here,

  • console.log("First!") runs immediately, it's synchronous.
  • setTimeout(..., 0) schedules the callback to run after the current call stack is empty, not instantly.
  • console.log("Second!") runs right after, also synchronous.
  • Once the main code finishes, the event loop checks the task queue.
  • The setTimeout callback is waiting there, and now it's executed, printing "Third!".
  • Even with 0ms delay, the function is deferred and will always run after all synchronous code finishes.

clearTimeout

You can use clearTimeout to clear the timeout scheduled with setTimeout.

const id = setTimeout(() => {
  console.log("This will never run!");
}, 3000);
 
clearTimeout(id); // Cancels the timeout

Here,

  • You set a timeout to run a function after 3 seconds.
  • The function is scheduled to print "This will never run!" after 3000 milliseconds (3 seconds).
  • setTimeout returns an id that represents this scheduled task.
  • Immediately after, you call clearTimeout(id);, this cancels the scheduled timeout using the id.
  • So the callback function never executes.

Why Use This?

To stop a timeout before it runs, for example:

  • If a user navigates away from a page.
  • If a condition changes and you no longer want the delayed action.
  • To prevent unnecessary work or errors.

setInterval

setInterval runs a function again and again with a fixed time gap.

This keeps going forever unless you stop it. That means your function will run again and again, on a fixed schedule, until you clear it using clearInterval().

Syntax:

setInterval(callback, intervalInMs, ...args);

Here, it runs the callback every intervalInMs milliseconds until you stop it.

Example:

setInterval(() => {
  console.log("Runs every 1 second!");
}, 1000);

Here,

  • setInterval schedules a function to run repeatedly every 1000 milliseconds (1 second).
  • The function inside logs: Runs every 1 second!

clearInterval

You can use clearInterval to stop the interval.

const id = setInterval(() => {
  console.log("This will be stopped!");
}, 1000);
 
setTimeout(() => {
  clearInterval(id);
  console.log("Stopped!");
}, 5000);

Here,

  • const id = setInterval(() => {...}, 1000); runs the function every 1 second.
  • Every second, it logs: "This will be stopped!".
  • The interval’s ID is saved in id, which you’ll use to stop it later.
  • Then you set a timeout to stop the interval: setTimeout(() => {...}, 5000);.
  • After 5 seconds, the setTimeout callback runs.
  • It calls clearInterval(id) to stop the repeating interval.
  • Then logs "Stopped!" once.
  • When you run this, for the first 5 seconds, every second you see: This will be stopped!.
  • After 5 seconds: Stopped!
  • And the interval stops and there will be no more logs from it.

Why use this?

  • Sometimes you want to run repeated actions but only for a limited time.
  • Use setTimeout + clearInterval combo to schedule when to stop the repeating action.

What is a Timer ID in setTimeout and setInterval?

Whenever you call setTimeout() or setInterval(), JavaScript returns a unique timer ID, just a number that represents that scheduled task.

You can store this ID in a variable, so you can cancel or clear it later.

Example:

const id = setTimeout(() => {
  console.log("Hello after 2 seconds!");
}, 2000);

Here, id will store a number (like 1, 2, etc.) that represents this timer.

If you change your mind and don’t want this to run:

clearTimeout(id);

Same goes for intervals:

const intervalId = setInterval(() => {
  console.log("Repeats every second!");
}, 1000);
 
// Later, stop it
clearInterval(intervalId);

Why store the ID?

Because setTimeout and setInterval just schedule the task. You need their IDs to cancel them before they execute or repeat again.


The this Context in Timer Callbacks

When using timers with regular functions (not arrow functions), be careful about the this context.

const obj = {
  name: "Shefali",
  greet() {
    console.log("Hello", this.name);
  },
 
  // This won't work as expected
  delayedGreet() {
    setTimeout(function () {
      console.log("Hello", this.name); // `this` is undefined or window
    }, 1000);
  },
 
  // This works correctly
  delayedGreetFixed() {
    setTimeout(() => {
      console.log("Hello", this.name); // Arrow function preserves `this`
    }, 1000);
  },
};
 
obj.greet(); // Output: Hello Shefali
obj.delayedGreet(); // Output: Hello <empty string>
obj.delayedGreetFixed(); // Output: Hello Shefali

Why this happens:

  • Regular functions in timers lose their original this context.
  • Arrow functions inherit this from their surrounding scope.
  • Use arrow functions or .bind() to preserve the correct this.

Common Mistakes

  • Forget to clear interval: It keeps running and wastes resources.

  • Wrong delay: setTimeout(fn, "1000") works, but always use numbers, not strings.

  • Assuming it's exact: Timers aren’t guaranteed to be precise. JavaScript is single-threaded and delay may stretch slightly if the main thread is busy. For example:

    for (let i = 0; i < 1000000000; i++) {
      // Blocking operation
    }
    setTimeout(() => console.log("This might be delayed"), 100);

Best Practices

  • Use setTimeout for delayed tasks (like showing a popup).
  • Use setInterval for polling, updating time, animations, but always clear it when done.
  • Store the timer ID in a variable if you plan to cancel it.
  • For smoother animations, prefer requestAnimationFrame() over setInterval.

Support my work!