Basics of Node.js and How It Works
1. What is NodeJS?
NodeJS is a framework built on the V8 JavaScript Engine, used to build web applications such as video clip sites, forums, and particularly niche social networking sites. NodeJS is an open-source framework widely used by thousands of developers around the world. It runs on multiple platforms such as Windows, Linux, and OS X, which is also an advantage. NodeJS provides rich libraries in various JavaScript Modules that help simplify programming and reduce development time.
2. Features of NodeJS
- Asynchronous: All NodeJS APIs are asynchronous (non-blocking), relying on the NodeJS Server and waiting for the server to return data. Moving the server to the next API call and the event notification mechanism in Node.js allows the server to respond to API calls before (Realtime).
- Fast execution: NodeJS is built on the V8 JavaScript Engine, so the execution of programs is very fast.
- Single-threaded but highly scalable: Node.js uses a single-threaded event-loop model. The event mechanism allows servers to respond without blocking, making the server highly scalable compared to traditional servers, which have limitations in handling requests. Node.js uses a single-threaded program, and similar programs can provide services to many more users compared to traditional servers like Apache HTTP Server.
- No buffering: NodeJS does not buffer any data; these applications are mostly output data.
- Licensed: NodeJS is licensed under the MIT License.
3. How does Node.js work?
The main idea behind Node.js is to use non-blocking I/O for real-time data tasks quickly. Because Node.js is highly scalable, it can handle many simultaneous connections with high throughput. Unlike traditional web applications where each request creates a new process that takes up system RAM, Node.js uses a single-threaded approach, combining non-blocking I/O to handle requests, which allows support for tens of thousands of simultaneous connections.
4. NPM: The Node Package Manager
When discussing Node.js, one cannot overlook the package manager, NPM, which is bundled with every Node.js installation. The idea behind NPM modules is similar to RubyGems: a collection of available functions that can be used, reusable components, and easy setup through an online repository with various version management.
You can find a list of modules on the NPM website or use the NPM CLI tool to automatically install modules with Node.js.
Some of the most popular NPM modules today include:
- expressjs.com/ – Express.js, a Sinatra-inspired web framework for Node.js, containing many essential applications for Node.js today.
- connect – Connect is an extension of the HTTP server framework for Node.js, providing a high-performance collection of “plugins” known as middleware; serving as a foundation for Express.
- Jade – A template engine inspired by HAML, a default part of Express.js.
- mongo and mongojs – MongoDB client wrappers to provide APIs for MongoDB’s object database in Node.js.
- redis – Redis client library.
- coffee-script – CoffeeScript compiler for developers to write their Node.js programs in CoffeeScript.
- underscore (lodash, lazy) – The most popular utility library in JavaScript, this package is used with Node.js, promising better performance through a slightly different execution approach.
- forever – Perhaps the most popular utility to ensure a Node.js script runs continuously. Keeps your Node.js process running in production in the face of unexpected failures.
5. Example of Node.js
Chat applications are the best example of real-time, multi-user applications running over various proprietary and open protocols on non-standard ports, capable of doing everything today with WebSockets running over standard port 80.
Chat applications are indeed the quintessential example of Node.js: it’s a rapid information exchange application, high traffic, data-intensive (but low computation) running on distributed devices. It’s also a great learning case as it’s simple but includes most of the patterns you will use in a typical Node.js application.
In the simplest example, we have a simple chat room on our website where people come and can exchange one or more messages (in reality, all of them). For example, there are three people on the website all connected to our message board.
On the server-side, we have a simple Express.js app doing two things:
- GET ‘/’ handles requests to serve web pages containing both a message board and a “Send” button to initiate a new message.
- A WebSocket server listening for new messages being sent by WebSocket clients.
On the client-side, we have an HTML page with some JavaScript handling the “Send” button click event, capturing the input messages and sending them via WebSocket, and listening for new messages coming from other WebSocket clients (i.e., messages sent by other users, which the server wants to broadcast to all clients).
Let’s analyze the process when a client sends a message:
- The browser catches the “Send” button click event through a JavaScript handler, captures the values from the input fields (i.e., text messages), and emits a WebSocket message using the client connected to the WebSocket server (initiated on the web page).
- The server-side part of the WebSocket connections receives the message and forwards it to all other connected clients using broadcasting methods.
- All clients receive the new message as a push notification through a client-side WebSocket component running on the webpage. Then, they retrieve the message content and update the webpage on-the-fly by adding the new posts to the broadcasted messages.
This is the simplest example. For a more robust solution, you might use a simple cache-based memory store like Redis. Or in a more advanced solution, a message queue can be used to route messages to clients with a more powerful distribution mechanism to handle temporary connection losses or message storage for offline users. But regardless of the improvements, Node.js will continue to operate under the basic principles: reacting to events, handling many concurrent connections, and maintaining fluidity in the user experience.
References