Scheduling: setTimeout and setInterval

JavaScript allows you not only to invoke the function right now but also a particular time later. The latter is known as a “scheduling call.”

Two main methods can be highlighted for it:

  1. setTimeout: calls a function once after a particularized delay.
  2. setInterval: calls a function repeatedly, beginning after some time, then repeating continuously at the given interval.

These methods are generally supported in all browsers, as well as Node.js.

setTimeout

For setTimeout this syntax is used:

let timerId = setTimeout(func | code, [delay], [arg1], [arg2], ...)

It has the following parameters:

  • func|code: a string or a function of code for executing. As a rule, it’s a function. A code string might be passed, but it’s not recommended.
  • delay: the before-running delay, in milliseconds, 0 by default.
  • arg1, arg2…: the function arguments ( IE9- doesn’t support them).

For example, the given code calls welcome() in a second, as follows:

function welcome() {
  console.log('Welcome to W3Docs');
}
setTimeout(welcome, 1000);

Along with the arguments:

function welcome(message, siteName) {
  console.log(message + ' to ' + siteName);
}
setTimeout(welcome, 1000, "Welcome", "W3Docs"); //Welcome to W3Docs

In case the first argument turns out to be string, JavaScript makes a function from it:

setTimeout("console.log('Welcome to W3Docs')", 1000);

But, it is recommended to use arrow functions and not strings.

For instance:

setTimeout(() => console.log('Welcome to W3Docs'), 1000);

We recommend to pass a function and not to run it.

It’s not a good idea to add brackets () after the function.

// wrong!
setTimeout(welcome(), 1000);

Cancel with clearTimeout

The setTimeout call returns a “timer-identifier” timerId used for canceling the invocation.

The following syntax is used for canceling:

let timeoutId = setTimeout(...);
clearTimeout(timeoutId);

In the example given below, the function is scheduled and then called off:

let timeoutId = setTimeout(() => console.log("Hello, dear user!"), 2000);
console.log(timeoutId); // timer identifier 
clearTimeout(timeoutId);
console.log(timeoutId); // same identifier (doesn't become null after canceling)

The alert output shows that the time identifier of the browser represents a number. The result can be different in other environments. So, there isn't any common specification for the methods.

setInterval

The syntax of the setInterval is the same as for the setTimeout:

let timerId = setInterval(func | code, [delay], [arg1], [arg2], ...)

The meaning is the same for all the arguments. But, unlike the setTimeout method, it invokes the function regularly after a particular interval of time.

Call clearInterval(timerId) for stopping upcoming calls.

Let’s check out an example:

// repeat with the interval of 2 seconds
let intervalTimerId = setInterval(() => console.log('start'), 2000); 
// after 5 seconds stop
setTimeout(() => {
  clearInterval(intervalTimerId);
  console.log('stop');
}, 5000);

Nested setTimeout

We can highlight two major ways to run something regularly. The first is setInterval, the second one is setTimeout, like here:

/** instead of:
let intervalTimerId = setInterval(() => console.log('start'), 1000);
*/ 
let intervalTimerId = setTimeout(function start() {
  console.log('start');
  intervalTimerId = setTimeout(start, 1000); // (*)
}, 1000);

The setTimeout schedules the upcoming call at the end of the current one (*).

The nested setTimeout method is more flexible than setInterval. For example, you want to write a service for sending a request to the server once in 5 seconds to ask for data. If the server is busy, the interval will be increased to 10, 20, 40 seconds, and more.

For instance:

let delay = 3000;
let intervalTimerId = setTimeout(function request() {
  //send request
  if (the request failed as the server was overloaded) {
    delay *= 2;
  }
  intervalTimerId = setTimeout(request, delay);
}, delay);

Consider that nested setTimeout can help you to set the delay between the invocations more accurately than setInterval.

Let’s correlate two code fragments. The setInterval is used by the first one:

let i = 1;
setInterval(function () {
  f(i++);
}, 1000);

The second code uses the nested setTimeout:

let i = 1;
setTimeout(function run() {
  f(i++);
  setTimeout(run, 100);
}, 100);

As for the setInterval the internal scheduler runs f(i++) every 100 milliseconds (ms).

The real delay between f calls for setInterval is shorter than inside the code.

Now, let’s check out the picture of the nested setTimeout:

The nested setTimeout ensures a fixed delay. The reason is that it plans a new call after the previous call.

Zero Delay setTimeout

There exists a unique use case: setTimeout(f, 0), or setTimeout(f) scheduling the execution of f. It schedules the function to run right after the current script.

For instance:

setTimeout(() => console.log("W3Docs"));
console.log("Welcome to");

Browsers set limitations on how often nested timers may run. The HTML5 standard states that after five nested timers, the interval must be at least 4 ms.

server-side JavaScript, there are no such limitations. It offers other ways of scheduling an immediate asynchronous job, such as setImmediate for Node.js.




Do you find this helpful?

Related articles