The Node.js Platform

Muhammad Zeeshan Ashraf
Dastgyr
Published in
6 min readApr 3, 2023

Node.js: a name that’s become synonymous with modern, scalable web development. Node.js is something we all love because of how it revolutionizes the development mindset and moving paradigm of mapping the real world to the Keep It Simple, Stupid (KISS) principle. But what exactly is Node.js?

In short, Node.js is a server-side JavaScript runtime that allows developers to build fast, scalable web applications using JavaScript. But it’s more than just another programming language or framework. Node.js represents a paradigm shift in web development, enabling developers to build highly performant, real-time applications that can handle thousands of concurrent connections.

Are you tired of building Node.js applications that quickly become unmanageable, with code that’s difficult to maintain and refactor? Have you struggled to scale your Node.js application without sacrificing performance? If so, you’re not alone. Node.js developers often face these challenges, especially as their applications grow in size and complexity.

Javascript Hell

But fear not! In this series of blog posts, we’ll deep dive into Node.js using “Node.js Design Patterns: Design and implement production-grade Node.js applications using proven patterns and techniques” book written by Mario Casciaro and Luciano Mammino where not only we are going to understand the modern design patterns but also establishing our base from the core of Node.js to grasp why its behavior is in an asynchronous manner along with the underlying system architecture. So, buckle up and get ready to discover the power of design patterns in Node.js development!

Node.js Philosophy

Every programming language has its ideology. Node.js principles have their bases from three pillars. Some of these principles are rooted in the vision of Node.js creator Ryan Dahl, while others are the result of the collaborative efforts of the community and charismatic figures within it. And let’s not forget the influence of the larger JavaScript movement, which has had a profound impact on the development of Node.js and its ecosystem. The four main principles or terra-S (SSSS) as I call them are described below:

1- Small Core: In the world of Node.js, less is often more. That’s why the Node.js core — the beating heart of this powerful runtime — is designed to be as lean and mean as possible, providing just the essentials and leaving the rest to the userland. Known for its minimalistic approach, the Node.js core provides a lean and efficient runtime that’s focused on delivering only the most essential features. By keeping the core small and focused, Node.js empowers developers to build custom solutions tailored to their specific needs.

2- Small Modules: This principle has its roots in the Unix philosophy, particularly in two of its precepts, which are as follows:
• “Small is beautiful.”
• “Make each program do one thing well.”

At the heart of this modular approach is the Don’t Repeat Yourself (DRY) principle, which Node.js takes to a whole new level. By breaking down applications into smaller, focused modules, developers can avoid duplicating code and reduce the risk of errors or inconsistencies. This not only saves time and effort but also ensures that code is more maintainable and scalable.

3- Small Surface Area: In Node.js, simplicity is the key to success. That’s why it’s common to define modules with just one clear entry point — whether it’s a function, class, or other building blocks. This approach maximizes clarity, minimizes confusion, and makes modules more flexible and maintainable.

4- Simplicity and Pragmatism: In the world of Node.js, simplicity trumps perfection. By keeping application design simple, we encourage community contributions, foster growth, and facilitate improvement. And thanks to the pragmatic nature of JavaScript, this approach is easy to adopt and embrace.

“The design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.”
Richard P. Gabriel

How Node.js Works

To gain an understanding of how Node.js work internally conception of the things behind the asynchronous nature is very important.

I/O is slow:

Let’s face the elephant in the room I/O (short for input/output) is the slowest operation in the computer universe. Data on the RAM can be accessed in nanoseconds while data on disk take milliseconds same in the case of network bandwidths. While many I/O operations are also dependent on humans so performance speed decrease by an order of magnitude.

Blocking I/O:

In the world of traditional blocking I/O programming, everything comes to a grinding halt when an I/O request is made. That’s because the function call associated with the request will block the execution of the thread until the operation is complete. It’s like hitting the pause button on your application — everything stops until the I/O operation is finished. This problem can be solved using multiple threads however threads are not cheap in terms of system resources — it consumes memory and causes
context switches — so having a long-running thread for each connection and not using it most of the time means wasting precious memory and CPU cycles.

multiple threads to process multiple connections

Non-Blocking I/O:

Non-blocking I/O is a game-changer, but it requires a different approach. Instead of waiting for data to be read or written, the system call returns immediately, allowing you to actively poll the resource within a loop until data is returned. However, this approach, known as busy waiting, can be inefficient and lead to wasted CPU time. It’s possible to handle different resources in the same thread, but it’s not always the most efficient option.

Event Demultiplexing:

Operating systems have a clever trick up their sleeve for juggling multiple tasks at once: the synchronous event demultiplexer. This wondrous mechanism can combine and split signals, keeping a watchful eye on numerous resources and returning a fresh event when necessary. These events are then dutifully processed, ensuring the associated resources are ready and waiting for action. Once all tasks have been tended to, the event loop kicks in, patiently waiting for new tasks to come their way.

event loop

The reactor pattern:

A reactor pattern is an approach in which the handler is associated with every I/O operation. A handler in Node.js is represented by a callback function. To handle I/O operations, the application sends a request to the Event Demultiplexer with a handler for when the task is complete. This call is non-blocking and control immediately returns to the app. The Demultiplexer generates events for each completed task and adds them to the Event Queue. The Event Loop then runs through the Queue, invoking the appropriate handlers for each event. These handlers can trigger new operations and add them to the Demultiplexer. Once all events are processed, the Event Loop blocks until new events are added to the Demultiplexer to start the cycle anew.

Libuv Node.js I/O Engine:

Every operating system has its unique interface for the event demultiplexer. Additionally, I/O operations can vary significantly based on the type of resources, even within the same OS. To unify the various event demultiplexer inconsistencies across different operating systems, the Node.js team created the libuv library. This powerful tool normalizes non-blocking behavior across different resource types and ensures compatibility with major operating systems. Libuv is the beating heart of Node.js and serves as the low-level I/O engine. It implements the reactor pattern and offers an API for event loop creation, event queue management, asynchronous I/O operations, and task queues. In short, it abstracts the underlying system calls and provides a powerful and standardized interface for Node.js applications.

Libuv Node.js I/O Engine

Node.js Recipe:

Node.js has a three-tier architecture. At the top level lies the Node.js API, implemented in JavaScript and containing core packages, streams, buffers, and more. The bottom level comprises the Chrome V8 engine, Libuv library, DNS, zlib, and other crucial components. The HTTP module, written in JavaScript, resides at the top level, while the bottom level hosts the http_parser, written in C. These components communicate via Node.js bindings.

Conclusion

Wrapping up for today we discuss many important fundamentals of Node.js internal working. Next time, we will go deep into one of the most fundamental topics of Node.js, its module system. Thanks, guys for being with me, and stay tuned.

Reference articles for further studies
https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
https://levelup.gitconnected.com/nodejs-runtime-environment-libuv-library-event-loop-thread-pool-5f5ecadc0318

--

--

Muhammad Zeeshan Ashraf
Dastgyr
Writer for

I am a Software Engineer and Programmer. I believe in power of change and i want change the world in better way by becoming an open source leader who help other