Skip to main content

The Event Loop

JavaScript is a single-threaded language. Under standard execution, this means it can only run one specific process at a time. If you write a loop that takes 5 minutes to calculate, the entire program completely freezes for those 5 minutes.

Node.js circumvents this freezing issue using the Event Loop, allowing it to handle concurrent operations like web server traffic dynamically.

Call Stack

The Call Stack executes your synchronous JavaScript code directly. It operates on a LIFO (Last In, First Out) principle. If you run a simple console.log("Start"), it goes to the stack, executes, and pops off instantly.

Web APIs (libuv)

When the Call Stack encounters an asynchronous task (like pushing an API request or reading a file using fs), it does not wait. It pushes the expensive task over to C++ libraries running in the background (specifically, the libuv library thread pool).

The Call Stack immediately continues processing the rest of your synchronous code.

The Callback Queue

Once the background task (e.g., waiting for the database query) completes, the background thread pushes the result into the Callback Queue.

Event Loop Tick

The Event Loop is a continuous cycle checking exactly two things:

  1. Is the regular Call Stack completely empty?
  2. Are there any pending, finished items waiting in the Callback Queue?

If the Call Stack is empty, the Event Loop takes the first item from the Callback Queue and pushes it up onto the Call Stack to execute the final resolution code.

console.log("Sync Task 1");

// Passed to background thread, waiting 2 seconds
setTimeout(() => {
console.log("Async Task");
}, 2000);

console.log("Sync Task 2");

// Console Execution output:
// "Sync Task 1"
// "Sync Task 2"
// ... (2 seconds pass and the Event loop pulls from the Queue) ...
// "Async Task"