Discover JavaScript Timers

setTimeout()

When writing JavaScript code, you might want to delay the execution of a function.

This is the job of setTimeout. You specify a callback function to execute later, and a value expressing how later you want it to run, in milliseconds:

setTimeout(() => {
  // runs after 2 seconds
}, 2000);

setTimeout(() => {
  // runs after 50 milliseconds
}, 50);

This syntax defines a new function. You can call whatever other function you want in there, or you can pass an existing function name, and a set of parameters:

const myFunction = (firstParam, secondParam) => {
  // do something
};

// runs after 2 seconds
setTimeout(myFunction, 2000, firstParam, secondParam);

setTimeout returns a timer identifier. In Node.js, this is a Timeout object that provides additional functionality, while in browsers it returns a numeric ID. You can store this identifier and use it to cancel the scheduled function execution:

const id = setTimeout(() => {
  // should run after 2 seconds
}, 2000);

// I changed my mind
clearTimeout(id);

In Node.js, the Timeout object provides additional methods:

  • timeout.ref(): Keeps the Node.js event loop active while the timer is running
  • timeout.unref(): Allows the Node.js event loop to exit even if the timer is still running
  • timeout.refresh(): Resets the timer's start time to the current time

Zero delay

If you specify the timeout delay to 0, the callback function will be executed as soon as possible, but after the current function execution:

setTimeout(() => {
  console.log('after ');
}, 0);

console.log(' before ');

This code will print

before
after

This is especially useful to avoid blocking the CPU on intensive tasks and let other functions be executed while performing a heavy calculation, by queuing functions in the scheduler.

Some browsers (IE and Edge) implement a setImmediate() method that does this same exact functionality, but it's not standard and unavailable on other browsers. But it's a standard function in Node.js.

setInterval()

setInterval is a function similar to setTimeout, with a difference: instead of running the callback function once, it will run it forever, at the specific time interval you specify (in milliseconds):

setInterval(() => {
  // runs every 2 seconds
}, 2000);

The function above runs every 2 seconds unless you tell it to stop, using clearInterval, passing it the interval id that setInterval returned:

const id = setInterval(() => {
  // runs every 2 seconds
}, 2000);

clearInterval(id);

Like setTimeout, setInterval returns a Timeout object in Node.js (and a numeric ID in browsers). This object provides the same additional methods (ref(), unref(), and refresh()).

It's common to call clearInterval inside the setInterval callback function, to let it auto-determine if it should run again or stop. For example this code runs something unless App.somethingIWait has the value arrived:

const interval = setInterval(() => {
  if (App.somethingIWait === 'arrived') {
    clearInterval(interval);
  }
  // otherwise do things
}, 100);

Recursive setTimeout

setInterval starts a function every n milliseconds, without any consideration about when a function finished its execution.

If a function always takes the same amount of time, it's all fine:

setInterval working fine

Maybe the function takes different execution times, depending on network conditions for example:

setInterval varying duration

And maybe one long execution overlaps the next one:

setInterval overlapping

To avoid this, you can schedule a recursive setTimeout to be called when the callback function finishes:

const myFunction = () => {
  // do something

  setTimeout(myFunction, 1000);
};

setTimeout(myFunction, 1000);

to achieve this scenario:

Recursive setTimeout

setTimeout and setInterval are available in Node.js, through the Timers module. In Node.js, these functions return a Timeout object that provides additional functionality for timer management.

Node.js also provides setImmediate(), which is equivalent to using setTimeout(() => {}, 0), mostly used to work with the Node.js Event Loop.