Deep Tech Point
first stop in your tech adventure

What is the difference between (nested) setTimeout and setInterval in JavaScript?

May 31, 2021 | Javascript

Usually, a piece of JavaScript code is executed synchronously, this means the code runs line after line as it’s written after hoisting in one thread. However, there might be situations when you need to run a block of your code at some point later in the future – when you need to delay the execution of some instructions. This concept of telling your code to work asynchronously is called ‘scheduling a call’ – as simple as that. There are two methods in JavaScript that enable to schedule a call – (nested) setTimeout() and setInterval(). A very simple explanation would say setTimeout() runs the code once after the timeout – it fires once or it runs the call only once after an interval, while setInterval() runs the code repeatedly, with the length of the timeout between each interval – it repeats the call, it fires again and again in intervals.

In this tutorial, you’ll learn how these two methods work, what is the difference between (nested) setTimeout and setInterval and we’ll give you some practical examples to understand these concepts a bit better.

Explaining the setTimeout() method

As said above in the introduction, setTimeout() method runs the code once after the timeout – it runs the call only once after an interval. The setTimeout() method is commonly used when you need to run your code a specified number of milliseconds from when the setTimeout() method was called.

The general syntax of the method is:

setTimeout(function, milliseconds);

Where the first parameter is a function or an expression in the JavaScript code to be executed after the second parameter indicates the number of milliseconds before the code is executed.

For example, this simple code below calls sayWelcome() after two seconds (logs ‘Welcome’ after 2 seconds):

function sayWelcome() {
    console.log('Welcome');
}

setTimeout(sayWelcome, 2000);

And you can pass arguments (in our case a message and user) with the function, like this:

function sayWelcome(message, user) {
    console.log(message + ', ' + user);
}

setTimeout(sayWelcome, 2000, 'Welcome', 'Alex'); // Welcome, Alex

In a case when the first argument is a string, you could tweak a situation, because JavaScript would create a function from it and the code would run due to JS historic legacy:

setTimeout('console.log("Welcome")', 2000);

However, in modern browsers this will produce an error because string evaluation is big no-no in JavaScript. It is not recommended to use strings for security reasons. Instead you should use functions:

setTimeout(() => console.log('Welcome'), 2000);

However, be careful to only pass a function and not run it. Occasionally, a developer might make a mistake by adding brackets () after the function, and he may not understand why the code won’t work. The reason is that setTimeout method will expect a reference to a function and in our case below sayWelcome() runs the function, and the result of its execution is passed to setTimeout. In our case the result of sayWelcome() is undefined, so the function won’t return anything, therefore nothing will be scheduled.

// this doesn't work 
setTimeout(sayWelcome(), 2000);

clearTimeout() method

In cases when you need to track the timeout, setTimeout() method returns a numeric timeout ID or ‘timer identifier’, let’s call it timeoutId, which is commonly used in connection with the clearTimeout() method. A call to setTimeout will return a timeoutId and we can use it to cancel the execution. The syntax to canceling the execution would look like this:

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

Next, we will schedule the function and then cancel it, because we changed our mind to run it. Obviously, nothing will happen:

let timeoutId = setTimeout(() => console.log("nothing will happen"), 2000);
console.log(timeoutId); // timer identifier or numeric timeout ID 

clearTimeout(timeoutId);
console.log(timeoutId); // timer identifier or numeric timeout ID that doesn't become null after canceling

Explaining the setInterval() method

Can you imagine an animation? Basically, something that is executed again and again like a GIF? This is what setInterval() method is about. The setInterval() method sets a delay for functions that are executed again and again like animations – it calls a function or executes a code snippet over and over again, with a fixed time delay between each call. setInterval() runs the code repeatedly – it repeats the call, in intervals. SetInterval() method returns an interval ID (the same as a call to setTimeout) and is unique to the interval, so you can remove it later by calling clearInterval(). We’ve shown an example with a clearTimeout() method and the principle is identical.

We’ve already indicated the setInterval() function is very closely related to setTimeout() and both methods even have same syntax:

setInterval ( function, milliseconds );

The essential difference lies in repetitiveness – setTimeout() fires the code only once while setInterval() repeats firing the code after the specified interval of time (unless you call the clearInterval() to stop further calls).

clearInterval() method

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

// setInterval alerst Welcome after every 4 seconds again and again
let timerId = setInterval(() => console.log('Hello'), 4000);

// However, with clearInterval and timerId we will stop the repeating and after 12 sec we will log Have a good day!
setTimeout(() => { clearInterval(timerId); console.log('Have a good day!'); }, 12000);

Timer continues ticking while showing alert

Another important thing to bring out is that the time goes on while the alert is shown. Therefore, if the code that we’ve shown above runs and we don’t dismiss the alert window for some time, the actual interval between alerts will be shorter than 4 seconds.

What about nested setTimeout?

Compared to the setInterval, the nested setTimeout is a more flexible method. With a nested setTimeout() method we can schedule the next call differently, and the scheduling depends on the results of the current call. A good example of using a nested setTimeout() method would be a data request to a server while taking into account the server might experience overload. For example, we can send a request to a server every 10 seconds, but if a server is overloaded, the call will be repeated not after 10 seconds, instead we will increase the interval to 20, 40, 80 etc. seconds. In this case, the code would look like this:

let serverDelay = 10000;

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

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

  timerId = setTimeout(function, serverDelay);

}, serverDelay);

In addition to scheduling the next call differently, nested setTimeout allows setting the delay between the executions more precisely than setInterval. In reality, for setInterval the real delay is less than in the code, which is expected because the time a function consumes on execution takes a part of the interval. On the other hand, the nested setTimeout guarantees a fixed delay, because a new call is planned at the end of the previous one.

Why choose setInterval() over setTimeout()?

Obviously, the first reason would be the repetitiveness. Do you need the code to be executed only once or do you need the code to repeat firing after the specified interval of time?

Another important issue to bring out is the delay between one triggering of the expression and the next. You should know that setTimeout() has a relatively long delay during the evaluation of the code and while the new setTimeout() is being set up. So if your code demands precise timing and if you need something to be repeated after certain intervals, then setInterval() or nested setTimeout() are the way to go.