Understanding the JavaScript Event Loop

Hero image for Understanding the JavaScript Event Loop. Image by Gift Habeshaw.
Hero image for 'Understanding the JavaScript Event Loop.' Image by Gift Habeshaw.

The JavaScript event loop is a core concept that explains how JavaScript handles asynchronous operations despite being singlethreaded. Understanding the event loop is really important when it comes to writing efficient, nonblocking code. In this article, I'll explore how the JavaScript event loop works, covering the call stack, task queue, and microtasks. Hopefully, by the end, you should hopefully understand how JavaScript manages concurrency and asynchronous behaviour.


What is the JavaScript Event Loop?

JavaScript is singlethreaded, meaning that it can execute one piece of code at a time. However, it manages to handle asynchronous tasks (like HTTP requests, timers, or user interactions) seamlessly. The event loop is the mechanism that allows JavaScript to:

  • Execute code.
  • Collect and process events.
  • Run queued tasks.

The event loop continuously checks the call stack and the task queue, ensuring nonblocking behaviour.


The Building Blocks of the Event Loop

The call Stack

The call stack is a data structure that keeps track of function calls. When a function is invoked, it's added to the top of the stack. Once it completes, it is removed from the stack.

const first = () => {  console.log("First");  second();};const second = () => {  console.log("Second");};first();

Execution Flow:

To illustrate this, the example above executes like this:

  1. first() is pushed onto the stack.
  2. Inside first(), second() is called and added to the stack.
  3. second() finishes and is popped off the stack.
  4. first() completes and is popped off the stack.

Web Apis

In browsers, Web APIs handle asynchronous operations like setTimeout, DOM events, and fetch. These APIs run outside of the JavaScript engine and interact with the event loop. For example:

console.log("Start");setTimeout(() => {  console.log("Timeout");}, 0);console.log("End");// Outputs:// Start// End// Timeout

Even with a delay of 0, setTimeout is handled asynchronously, allowing synchronous code (console.log("End")) to execute first.

Task Queue (Callback Queue)

Once an asynchronous operation completes, its callback is placed in the task queue. It waits for the call stack to be empty before it runs.

Microtasks Queue

Microtasks (promises, MutationObserver, etc.) are processed after the current task completes but before the event loop moves to the next task.

console.log("Start");Promise.resolve().then(() => {  console.log("Microtask");});console.log("End");// Outputs:// Start// End// Microtask

Just to add to the confusion a little more, promises are microtasks and are prioritised over setTimeout callbacks.


The Event Loop in Action

Simplified Event Loop Flow:

  1. Execute synchronous code (call stack).
  2. Process microtasks.
  3. Render updates (if needed).
  4. Process tasks from the task queue.
  5. Repeat.

Example Combining All Concepts

Here's an example which (I hope) illustrates all of these concepts combined together:

console.log("1");setTimeout(() => console.log("2"), 0);Promise.resolve().then(() => console.log("3"));console.log("4");// Outputs:// 1// 4// 3// 2

Explanation:

  • 1 and 4 are synchronous, and are executed immediately.
  • The promise (3) is a microtask, so it is executed after the current stack clears.
  • setTimeout (2) is in the task queue, and is processed after microtasks.

Wrapping up

Understanding the JavaScript event loop is fundamental to understanding how asynchronous code works. By knowing how the call stack, microtasks, and task queues interact, you can write more efficient, nonblocking applications.

Key Takeaways

  • JavaScript is singlethreaded but handles asynchronous tasks through the event loop.
  • The call stack executes synchronous code, whilst asynchronous tasks wait in the task queue.
  • Microtasks (promises) are prioritised over regular tasks (like setTimeout).
  • Understanding the event loop helps debug, optimise performance, and avoid pitfalls like callback hell.

Understanding the event loop helps you write JavaScript applications that handle asynchronous tasks more predictably and perform efficiently.


Categories:

  1. Cross‑Browser Compatibility
  2. Development
  3. ES6
  4. Front‑End Development
  5. Guides
  6. JavaScript