#1 How Nodejs works? : Behind The Scene Series

#1 How Nodejs works? : Behind The Scene Series

Discovering How Asynchronous JavaScript Powers Node.js

Node.js is one of the most widely used technologies for building fast, scalable network applications. But what exactly is going on under the hood? How does Node.js handle millions of requests without breaking a sweat? In this post, we’ll dive deep into how Node.js works, taking a peek behind the scenes to understand its event-driven architecture, non-blocking I/O model, and the power of JavaScript on the server side.

What is Node.js ?

Imagine JavaScript is a talented musician who normally only plays at home (inside your browser). Now, with Node.js, this musician can perform live on stage in a huge concert hall (the server).
Node.js is a runtime environment that allows you to run JavaScript on the server side, outside of the browser. It uses Google’s V8 engine (the same engine that powers Chrome) to execute JavaScript.

The Event-Driven Architecture: The Waiter Analogy

To understand how Node.js works, picture this analogy:

Imagine a busy restaurant with a single waiter. This waiter takes orders from several customers. Now, instead of waiting for the chef to prepare each order before serving the next customer, the waiter simply jots down the order, hands it to the kitchen, and moves on to the next table. While the chefs are busy cooking, the waiter continues to take more orders, responding to customers only when their food is ready. This keeps the workflow smooth, even if the kitchen is swamped.

In Node.js, this waiter represents the Event Loop, which is the core of Node.js's event-driven architecture. Rather than handling one request at a time (like traditional server models), Node.js listens for events, processes them quickly, and moves on, making the most of its non-blocking I/O system.


What is Non-Blocking I/O?🏃‍♂️

Node.js uses non-blocking I/O. This means that when a request is made that requires a slow operation (like reading a file), Node.js doesn’t wait around for the operation to finish. Instead, it kicks off the operation and moves on to handle the next task. Once the slow operation is done, Node.js is notified via a callback and picks up where it left off.

Think of it like sending a friend a text to pick up groceries. You don’t sit by the phone waiting for them to reply—you go about your day, and when they respond, you handle it.


Single Threaded, Yet Concurrent?🤔

One of the most surprising things about Node.js is that it is single-threaded—meaning it can only run one task at a time.

💡
So how does it handle so many requests concurrently?

This is where the Event Loop and libuv come in. While Node.js uses a single thread to execute JavaScript, it delegates time-consuming tasks (like network requests or file system operations) to a background thread pool managed by libuv, an open-source library that provides Node.js with its asynchronous I/O behavior.

When one of these background tasks finishes, it passes the result back to the main thread, which is then processed by the event loop. This is how Node.js achieves concurrency without having to manage multiple threads.

Understanding Node.js Code Flow: From Script to Event Loop

  1. Entry Point (index.js file)
  • Node.js begins by executing the file you specify (e.g., index.js). This is the starting point for your code.

2. Main Thread

  • The main thread handles the execution of your code initially. Node.js uses a single main thread to execute the top-level code.

3. Initialization of the Project

  • Node.js initializes your project by setting up the environment, handling dependencies, and getting ready to execute the script.

4. Top-Level Code Execution

  • After the project initialization, Node.js starts executing your top-level code (like functions, variables).

5. Requiring Modules

  • Node.js loads any required modules, such as fs (file system) or http, using the require() function.

6. Event Callback Registration

  • If your code involves asynchronous operations (like reading a file or handling a network request), Node.js registers the callbacks to execute once those operations are completed.

  • The readFile operation doesn't block the rest of the code, allowing Node.js to move on.

7. Event Loop Starts

  • Node.js now enters the Event Loop, where it continuously checks for tasks like I/O operations, timer events, etc. It processes the events asynchronously, handling the callbacks as the tasks complete.

8. Thread Pool for I/O Operations

For CPU-intensive or I/O tasks (like reading/writing files or database queries), Node.js uses a Thread Pool (managed by libuv). The event loop delegates these tasks to the pool while continuing with other work.

const fs = require('fs'); // importing a module

console.log('Start the Node.js app...'); // top level code executes first

/* 
Reading a file (asynchronous task) is a cpu intensive task
so they are handled by thread pools
*/
fs.readFile('example.txt', 'utf8', (err, data) => {
    if (err) throw err;
    console.log('File content:', data);  // This happens later
});

console.log('Node.js app continues while file is being read...');

Output:

Start the Node.js app...
Node.js app continues while file is being read...
File content: (content of example.txt)

Conclusion: Magic behind Node.js

By now, you’ve seen how Node.js works its magic behind the scenes. With a single thread and a clever event loop, it handles multiple tasks without breaking a sweat. Think of it like a talented juggler—keeping many balls (tasks) in the air, catching and tossing them at the right time, all while staying cool under pressure.

This efficiency is what makes Node.js perfect for real-time applications, like chat systems or API servers. Next time you run a piece of code, just remember—Node.js isn’t just “running” your JavaScript; it's orchestrating a whole symphony of events in the background, effortlessly juggling tasks so your app can run smoothly!

What’s Next?

Thanks for reading this blog. I tried to keep it as simple and interesting so its easy when beginner read this.

In this first post, we’ve unveiled how Node.js efficiently handles tasks and serves as the backbone of many web applications. Stay tuned for the next post, where we’ll explore how another powerful technology works behind the scenes!

References

  1. Official documentation

  2. Github

  3. 6 Best Articles on Nodejs