Scheduling: setTimeout and setInterval

Pranay Chauhan
Last Updated: May 13, 2022

Introduction

Have you ever needed to schedule your program to be run at a specific time? 

When building web applications, we may require scheduling a javascript function call.

That is when we come across the need to use setTimeout and setInterval. This functionality is very important in javascript; this enables us to execute our program at the time we specify. This functionality is really useful in building time-based applications and real-time user interfaces.

In this article, we will learn about the scheduling techniques in Javascript and the implementation of setTimeout and setInterval.

Scheduling in Javascript

As discussed earlier, we can also decide to execute a function not at the moment but after a specific interval later. That is called “scheduling a call”.

There are two methods for scheduling in javascript:

  • setTimeout is a method in javascript that allows us to run a function once after a time interval.
  • setInterval is a javascript method that will enable us to run a function repeatedly after every time interval.


The methods mentioned above are not a part of the javascript framework. Most environments have an internal scheduler and provide these methods. In particular, These methods are supported in all browsers and Node.js.

setTimeout

Syntax

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

Understanding the Parameters

func|code

This parameter describes the function or a string of code to be executed. This usually is a function. For historical reasons, some code strings can also be passed as the parameter; however, it is not recommended to do so.

delay

This parameter tells about the delay, which is to be waited for before executing the code. This value is in milliseconds (1000ms = 1 second), and by default, this value is 0.

arg1, arg2…

Arguments for the function (not supported in IE9-)

For instance, this code calls sayHi() after one second:

function sayHi() {
 alert('Hello');
}

setTimeout(sayHi, 1000);


With arguments:

function sayHi(phrase, who) {
 alert( phrase + ', ' + who );
}

setTimeout(sayHi, 1000, "Hello", "John"); // Hello, John


If the first argument is a string, JavaScript creates a function.

So, this will also work:

setTimeout("alert('Hello')", 1000);


It is not recommended to use strings like this, so we should use arrow functions as shown below:

setTimeout(() => alert('Hello'), 1000);

Passing a function

New programmers generally sometimes make the mistake of adding brackets after the function.

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


That will not work as setTimeout expects a reference to the function. Hereby using the brackets, we are running the function, and the result of the function’s execution is getting passed to setTimeout. In the example we have used,  the result of sayHi() is undefined, so nothing is scheduled.

Cancelling setTimeout with clearTimeout

A call to setTimeout returns a “timer identifier” timerId that we can use to cancel the execution.

The syntax to cancel:

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


In the code below, we schedule the function and then cancel it (changed our mind). As a result, nothing happens:

let timerId = setTimeout(() => alert("never happens"), 1000);
alert(timerId); // timer identifier

clearTimeout(timerId);
alert(timerId); // same identifier (doesn't become null after canceling)


As we can see from the alert output, the timer identifier is a number in a browser. In other environments, this can be something else. For instance, Node.js returns a timer object with additional methods.

Again, there is no universal specification for these methods, so that’s fine.

Timers are described in the timers section of the HTML5 standard for browsers.

setInterval

The setInterval method has the same syntax as setTimeout:

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


All arguments have the same meaning. But unlike setTimeout, it runs the function not only once but also regularly after the given interval of time.

To stop further calls, we should call clearInterval(timerId).

The following example will show the message every 2 seconds. After 5 seconds, the output is stopped:

// repeat with the interval of 2 seconds
let timerId = setInterval(() => alert('tick'), 2000);

// after 5 seconds stop
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);

Note

Time goes on while the alert is shown.

In most of the browsers, the internal timer continues “ticking” while showing alert or any other prompt.

If you would run the code shown above, and if we do not cancel the alert window for some time, then the next alert will be displayed as soon as you do it. And the actual interval between the alerts will be shorter than 2 seconds.

Nested setTimeout

There are two ways of running something regularly.

One is setInterval. The other one is a nested setTimeout, like this:

let timerId = setTimeout(function tick() {
 alert('tick');
 timerId = setTimeout(tick, 2000); // (*)
}, 2000);


The setTimeout above schedules the next call right at the end of the current one (*).

The nested setTimeout is a more flexible method than setInterval. This way, the next call may be scheduled differently, depending on the results of the current one.

For instance, we need to write a service that sends a request to the server every 5 seconds asking for data, but if the server is overloaded, it should increase the interval to 10, 20, 40 seconds…

Here is the pseudocode

let delay = 5000;

let timerId = setTimeout(function request() {
 //send request

 if (request failed due to server overload) {
   // increase the interval to the next run
   delay *= 2;
 }

 timerId = setTimeout(request, delay);
}, delay);


And if the functions that we’re scheduling are CPU-hungry, then we can measure the time taken by the execution and plan the next call sooner or later.

Nested setTimeout allows to set the delay between the executions more precisely than setInterval.

Let’s compare two code fragments. The first one uses setInterval:

let i = 1;
setInterval(function() {
 func(i++);
}, 100);


The second one uses nested setTimeout:

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


For setInterval the internal scheduler will run func(i++) every 100ms:

Source: javascript.info

Did you notice?

The real delay between func calls for setInterval is less than in the code!

That’s normal because the time is taken by func's execution “consumes” a part of the interval.

It is possible that func's execution turns out to be longer than we expected and takes more than 100ms.

In this case, the engine waits for func to complete, then checks the scheduler and if the time is up, runs it again immediately.

In the edge case, if the function always executes longer than delay ms, then the calls will happen without a pause at all.

And here is the picture for the nested setTimeout:

 

The nested setTimeout guarantees the fixed delay (here 100ms).

That’s because a new call is planned at the end of the previous one.

Garbage collection and setInterval/setTimeout callback

When a function is passed in setInterval/setTimeout, an internal reference is created to it and saved in the scheduler. It prevents the function from being garbage collected, even if there are no other references to it.

// the function stays in memory until the scheduler calls it
setTimeout(function() {...}, 100);


For setInterval, the function stays in memory until clearInterval is called.

There’s a side-effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don’t need the scheduled function anymore, it’s better to cancel it, even if it’s very small.

Zero delay setTimeout

There’s a special use case: setTimeout(func, 0), or just setTimeout(func).

This schedules the execution of func as soon as possible. But the scheduler will invoke it only after the currently executing script is complete.

So the function is scheduled to run “right after” the current script.

For instance, this outputs “Hello”, then immediately “World”:

setTimeout(() => alert("World"));
alert("Hello");


The first line “puts the call into the calendar after 0ms”. But the scheduler will only “check the calendar” after the current script is complete, so "Hello" is first, and "World" – after it.

There are also advanced browser-related use cases of the zero-delay timeout that we’ll discuss in the chapter Event loop: microtasks and macrotasks.

Note: Zero delay is, in fact, not zero (in a browser)

In the browser, there is a limitation on how often nested timers can be run. The HTML5 standards say that the interval is forced to be at least 4 ms after five nested timers.

Frequently Asked Questions (FAQs)

  1. What is scheduling in javascript?
    When we want to execute a certain code snippet at a specific time period, we use the technique of scheduling in javascript.
     
  2. What does setTimeout do?
    setTimeout is a method in javascript that allows us to run a function once after a time interval.
     
  3. What does setInterval do?
    setInterval is a method in javascript that allows us to run a function repeatedly after every time interval.

Key Takeaways

We learned about the concept of scheduling in javascript. This is an interesting technique of scheduling in javascript that allows us to schedule the time when we want our code to run. This article also explained the implementation setTimeout and setInterval in javascript.

You can also expand your knowledge by referring to these articles on Javascript.

For more information about the react framework for frontend development, get into the entire Frontend web development course.

Happy Learning!
 

Was this article helpful ?
0 upvotes

Comments

No comments yet

Be the first to share what you think