BACK TO JOURNAL
June 28, 20267 min read

Deep Dive: The JavaScript Event Loop & Concurrency Model

JavaScript is single-threaded, yet it handles thousands of concurrent operations seamlessly. Let's break down microtasks, macrotasks, and how the engine schedules execution.

JavaScriptAsynchronousNode.js

When I first started learning JavaScript, the concept of a single-threaded language handling network requests, timers, and button clicks concurrently was mind-bending. How does it manage multiple operations without blocking?

The answer lies in the Event Loop.

The Anatomy of Execution

JavaScript execution runs on a single Call Stack. When asynchronous code executes (e.g., fetch, setTimeout, fs.readFile), the JS runtime offloads this execution to the Web APIs (in the browser) or C++ APIs (in Node.js). Once complete, the callback is pushed to one of two queues:

1. Microtask Queue: Primarily for promise callbacks (Promise.then, catch, finally) and queueMicrotask.

2. Macrotask Queue (Callback Queue): For setTimeout, setInterval, and I/O operations.

The Loop Cycle

The Event Loop follows a strict sequence:

1. It executes all functions in the Call Stack until it is empty.

2. It executes all pending tasks in the Microtask Queue.

3. It renders UI updates (in browsers).

4. It takes one task from the Macrotask Queue and executes it.

5. Repeat.

Here is a quick code puzzle to test your understanding:

console.log('1. Start');

setTimeout(() => {
  console.log('2. Timeout');
}, 0);

Promise.resolve().then(() => {
  console.log('3. Promise');
});

console.log('4. End');

If you guessed the output is:

1. Start
4. End
3. Promise
2. Timeout

You are correct! Even though setTimeout has a delay of 0, the Promise callback goes into the Microtask Queue, which executes *before* the Macrotask Queue gets checked. Understanding these mechanics is vital when building real-time dashboards like Swift Delivery.

S

Showaib Hossain

Mathematics Honors & MERN Developer

Get in touch →