Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

The event loop

Some actions take time: waiting for a timer, a server response, a file download. JavaScript does not stand still while they happen; it carries on and comes back to the result later. To write such code without surprises, you need to know in which order it runs.

Synchronous code

Ordinary code is called synchronous: statements run strictly in order, and the next one starts only after the previous one has finished:

console.log('One');
console.log('Two');
console.log('Three');
// One
// Two
// Three

JavaScript is single-threaded: at any moment it runs only one statement. Two functions cannot run at the same time.

Asynchronous code

Asynchronous code is code that starts now and finishes later. The setTimeout() function postpones a call to another function by a given number of milliseconds:

setTimeout(() => {
  console.log('300 ms have passed');
}, 300);
// 300 ms have passed

While the timer waits, JavaScript is free to run other code.

The task queue

When a timer fires, its function does not run immediately; it joins the task queue. JavaScript takes tasks from the queue only once the current code has finished:

console.log('Start');
 
setTimeout(() => {
  console.log('Timer');
}, 0);
 
console.log('End');
// Start
// End
// Timer

Even with a zero delay the timer ran last: all the main code finished first.

The event loop

The mechanism that checks the queue over and over and starts the next task is called the event loop. Its work can be described like this:

StepWhat happens
1All the current synchronous code runs
2All microtasks run — promise handlers
3One task is taken from the queue, for example a timer function
4Back to step 2 — as long as there are tasks

Microtasks

Promise handlers (covered in the next lessons) go into a separate microtask queue. It runs before ordinary tasks:

setTimeout(() => console.log('Timer'), 0);
 
Promise.resolve().then(() => console.log('Promise'));
 
console.log('Plain code');
// Plain code
// Promise
// Timer

Long code delays everything

While synchronous code is running, no task from the queue can start. This loop keeps JavaScript busy for 200 ms, and the timer waits for it to end:

const start = Date.now();
 
setTimeout(() => {
  const waited = Date.now() - start;
  console.log(waited >= 200); // true
}, 0);
 
while (Date.now() - start < 200) {
  // just waiting
}

In the browser the whole page freezes for that time: buttons do not respond and animations stop.

Common mistake

Expecting setTimeout(..., 0) to run immediately. The delay is only the minimum waiting time: the function starts no earlier than the current code and all microtasks have finished. If you need the result right away, do not put the code in a timer; if you need "first this, then that", use promises and await.

Thanks for reading!

Donate to the site — we work hard for you.