Register to get access to free programming courses with interactive exercises

Timers JS: Asynchronous programming

Timers have their own place in the world of asynchronous programming. They allow you to make any function execute later. The most important function for working with timers is setTimeout(f, delay)

const f = () => console.log('hey!');
setTimeout(f, 1000);

In the code above, the f function will wait at least a second to execute. This is told by the second parameter, which passes the time in milliseconds (as the second parameter) to wait before the function given in the first parameter will run. For historical reasons, timers have a minimum delay that they always observe, which is four milliseconds. In other words, there is no difference between setTimeout(f, 1), setTimeout(f, 3) and setTimeout(f, 4), they'll all wait at least 4 milliseconds.

What are timers for? They have many different uses. When it comes to browsers, it could include automatically hidden elements, such as notifications. Another example is a regular (e.g., every 5 seconds) Ajax requestfor new data. In servers, timers are used less frequently, but they're still relatively common; they can be used to break up a large synchronous operation into several pieces, allowing other code to execute.

In operating systems, this behavior is called cooperative multitasking. It allows you to create a sense of parallel code execution, even if it isn't really what's happening.

A function passed to a timer isn't executed in the current call stack, which means that all the features and approaches we discussed earlier apply to timers. Timer errors can't be tracked with try/catch, you have to use callbacks for that.

const f = () => console.log('hey!');
console.log('before timeout');
setTimeout(f, 1000);
console.log('after timeout');
// the script doesn't end, it waits for the timers to execute


node index.js

before timeout
after timeout

Try and answer this question: Can timers guarantee an exact start after a specified time interval? They actually can't. It all depends on what's being done right now. The timers are checked by the runtime when there's no code left in the current call stack. If you run a heavy calculation that doesn't stop for a long time, all the callbacks and timers will wait until the calculation is done. In fact, this means that the timers set the minimum time after which they can be started.

This feature has two important implications:

  • Try to minimize the time it takes to perform long calculations. For example, by breaking them down into steps.
  • Don't count on the accuracy of call times. It will always be higher.

Timers can be not only created, but also canceled. The setTimeout call returns a special value, the timer ID. If you pass it to the clearTimeout function, the timer will be canceled:

const f = () => console.log('hey!');
console.log('before timeout');
// In browsers, the timer identifier is a numeric value
// In node.js, it's an object
const timerId = setTimeout(f, 1000);
console.log('after timeout');


node index.js

before timeout
after timeout

The fact that the asynchronous function returned the timer ID does not contradict what we said earlier about returns in asynchronous functions. An asynchronous function cannot return the result of an asynchronous operation, but it can return something else that was done synchronously within it. In the case of timers, the timer ID is returned synchronously, but the timer itself is executed asynchronously.

A common mistake made by beginners is not passing the function itself to the timer, but instead calling it. It usually happens they need to pass some predefined arguments into a function:

const f = (message) => console.log(message);
console.log('before timeout');
setTimeout(f('hey!'), 1000);
console.log('after timeout');


node index.js

before timeout
    throw new ERR_INVALID_CALLBACK();

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function

It didn't get to the last log because the script crashed on the setTimeout, call because it was expecting a function to come in, but it didn't (the call in the example returned undefined).

There are three ways to pass data into a function:

Additional parameters in setTimeout

All arguments passed to setTimeout after the second argument (time) automatically become arguments to the function that the timer calls.

const f = (a, b) => console.log(a + b);
setTimeout(f, 1000, 5, 8);
// =>  13

Wrapper Function

The most common way is to create a wrapper function. This method is better than the previous one because of its transparency; you can immediately see what's happening.

const f = (a, b) => console.log(a + b);
setTimeout(() => f(5, 8), 1000);
// =>  13


The last way is to use the bind function. The main purpose of this function is to change the context of a function. But it can also be used if you want to apply the function partially

const f = (a, b) => console.log(a + b);
// the first parameter is null because the context doesn't change
setTimeout(f.bind(null, 5, 8), 1000);
// =>  13

Calling this function returns a new function with the arguments applied.

It's important to understand that the timer doesn't make the operation (i.e., the one performed when the function passed to setTimeout is called) asynchronous; the timer only delays its execution time. If the operation itself is synchronous, it will block the main program execution flow after it starts, and everything else will wait for it to finish.


The setInterval function has exactly the same signature as setTimeout. The essence of the arguments is the same. The difference is that setInterval does not automatically start the function once, but executes it until it's explicitly stopped via clearInterval. The time between starts is equal to the value of the second parameter.

const id = setInterval(() => console.log(new Date()), 5000);
setTimeout(() => clearInterval(id), 16000);

// node index.js
// 2019-06-05T19:05:28.149Z
// 2019-06-05T19:05:33.172Z
// 2019-06-05T19:05:38.177Z

The timer can be stopped from inside by using its id in the callback.

let counter = 0;
const id = setInterval(() => {
  counter += 1;
  if (counter === 4) {
  console.log(new Date());
}, 5000);

Recommended materials

  1. setTimeout
  2. setInterval

Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
hours of theory

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing:">Bookmate</span>
<span class="translation_missing" title="translation missing:">Healthsamurai</span>
<span class="translation_missing" title="translation missing:">Dualboot</span>
<span class="translation_missing" title="translation missing:">Abbyy</span>
Suggested learning programs

From a novice to a developer. Get a job or your money back!

Frontend Developer icon
Development of front-end components for web applications
start anytime 10 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.