DEV Community

MD Masud Ur Rahman
MD Masud Ur Rahman

Posted on • Originally published at hashnode.com

How Node.js Actually Works (A Beginner's Mental Model)

Recently, I went down a rabbit hole trying to understand how Node.js handles asynchronous operations under the hood. I took a bunch of notes, refined them to make sense of the chaos, and wanted to share the mental model that finally made it "click" for me. If you are a beginner like me, I hope this helps you too!


What Node.js Actually Is

Node.js is a server-side JavaScript runtime environment. It takes the V8 JavaScript engine (the exact same engine that powers Google Chrome) out of the browser and wraps it in C++ bindings.

This allows JavaScript to break out of the browser sandbox and interact directly with the Operating System, file systems (fs), and network protocols.


How It Executes Code (The Delegation Model)

JavaScript is strictly single-threaded. This means its main execution space (the V8 Call Stack) can only process one operation at a time. To prevent your server from freezing during slow tasks (like querying a database), Node.js uses a delegation architecture:

  1. Encounter & Delegate: When JavaScript hits an operation it cannot execute directly on the main thread (such as reading from disk or fetching from a remote API), V8 immediately delegates that task to Node's underlying C++ background engine (libuv).

  2. Registers & Frees the Stack: Node hands libuv the background task alongside a reference to your callback. V8 finishes executing the initial setup function immediately and pops it off the Call Stack. This frees the main JavaScript thread to instantly handle other users or execute the rest of your script.

  3. Background Work: While JavaScript continues executing code on the main thread, libuv carries out the heavy lifting in the background using OS kernel facilities or a background Worker Thread Pool.

  4. Task Queue Resolution: When libuv finishes the background work, it pushes the completed result along with its callback into the Task Queue.

  5. Resuming Execution: The Event Loop constantly monitors the V8 Call Stack. Once it detects that the Call Stack is completely empty, it picks up the callback from the Task Queue, pushes it back onto the V8 Call Stack, and JavaScript resumes executing the rest of the code.


Visualizing the Flow

Here is a simple architectural map of how V8 and C++ work together:


      [1] JAVASCRIPT CODE
      fs.readFile('data.json', callback) 
               |
               v
  [2] V8 ENGINE (Call Stack)
      - Looks up function in C++ Binding Registry
               |
               v
  [3] C++ BINDING BRIDGE
      - Registers callback with libuv & returns to V8
               |
               +-----------------------------------+
               |                                   |
               v                                   v
  [4] V8 CONTINUES MAIN THREAD            [5] LIBUV (C++ Thread / OS Kernel)
      - Call stack is freed!       - Reads file from physical disk
      - Runs next lines of JS code                 |
                                                   v
                                          [6] TASK COMPLETE
                                    - Pushes result to Task Queue
                                                   |
                                                   v
                                          [7] EVENT LOOP
                               - Detects V8 Call Stack is empty
                        - Moves callback back onto V8 Call Stack

Enter fullscreen mode Exit fullscreen mode

If we write a simple script, we can see this exact delegation happening in real-time:

const fs = require('fs');

console.log("1. V8 runs this immediately on the Call Stack.");

// V8 delegates this to Node (libuv), empties the stack, and moves on! 
fs.readFile('database.json', (err, data) => { console.log("3. The Event Loop pushes this back to V8 when the background work is done."); });

console.log("2. V8 runs this without waiting for the file to finish reading.");
Enter fullscreen mode Exit fullscreen mode

If you run this code, it will always print in this exact sequence:

1. V8 runs this immediately on the Call Stack.

2. V8 runs this without waiting for the file to finish reading.

3. The Event Loop pushes this back to V8 when the background work is done.
Enter fullscreen mode Exit fullscreen mode

The main thread never blocked for a single millisecond!

Pretty cool i guess \+_+/.

Top comments (0)