logo
Published on

Concurrency Model and the Event Loop in JavaScript

Authors
  • avatar
    Name
    Nadir Tellai

Understanding JavaScript's Concurrency Model and the Event Loop

Introduction

JavaScript is often described as a single-threaded, non-blocking language, a characterization that might seem contradictory at first glance. How can a language that operates on a single thread handle multiple tasks without blocking the execution of other operations? The answer lies in JavaScript's unique concurrency model, which efficiently manages the execution of code, events, and messages.

The Concurrency Model of JavaScript

the event loop is the most important part off of JavaScript's concurrency model, This model allows JavaScript to perform non-blocking operations, despite being single-threaded, by offloading tasks and managing the execution of callbacks.

Key Components:

  1. Call Stack: The call stack is where JavaScript keeps track of function calls. It operates on a Last In, First Out (LIFO) principle, adding function calls to the stack and popping them off as they are completed.

  2. External API: JavaScript can make calls to external APIs like Web APIs in browsers, for operations that need to occur asynchronously, like setTimeout, HTTP requests, or event listeners.

  3. Callback Queue: Once an asynchronous operation is complete, its callback function is moved to another FIFO stack called the callback queue, waiting to be executed.

  4. Event Loop: The event loop is the orchestrator of this entire process. It continuously checks the call stack; if the stack is empty and there are functions in the callback queue, it dequeues the function and pushes it onto the call stack.

Code Example

Let's look at a simple code example to illustrate these concepts:

console.log("Start");

setTimeout(function timeoutCallback() {
    console.log("Timeout completed");
}, 2000);

console.log("End");

Code Walkthrough:

Code Walkthrough

  1. console.log("Start") is pushed to the call stack, executed, and then popped off.

  2. setTimeout with its callback timeoutCallback is pushed to the call stack. The browser handles the timer (an external API). The setTimeout function is then completed and popped off the call stack.

  3. console.log("End") is pushed to the call stack, executed, and then popped off.

  4. After 2 seconds, timeoutCallback is moved from the Web API environment to the callback queue.

  5. The event loop checks the call stack. Finding it empty, it moves timeoutCallback from the callback queue to the call stack.

  6. timeoutCallback is executed, logging "Timeout completed".

This flow demonstrates how JavaScript handles asynchronous operations, using the event loop and other components to manage tasks without blocking the main thread.

The visualization was generated by Loupe a tool to help you understand the event loop by Philip Roberts.

I also recommend watching his video "What the heck is the event loop anyway?" on YouTube.