Almost 30 years later, JavaScript, or simply JS, has matured into a multi-paradigm language that runs both inside a web browser and in standalone server-side runtime environments.
It is estimated that virtually every website in the world uses JS, and since the creation of Node.js, millions of systems have been running server-side JS.
This article will explain what Node.js is, how popular it has become, and when development teams should consider using it.
Node.js: running JavaScript outside the browser
For nearly two decades, JavaScript was confined to mainly client-side scripting inside the web browsers, with its place denoted by the ubiquitous <script> tag. It was primarily used for DOM manipulation and reacting to user-triggered events. There were some attempts to create a server-side runtime environment for JS (like Netscape's LiveWire Pro Web), but they never reached relevant popularity. Other attempts to create dynamic web pages were Flash and Java Applets; both currently reached their end-of-life.
In 2009, Ryan Dahl wrote the first version of Node.js to create an alternative to the Apache Server while also offering a better model for handling requests in a non-blocking way that would improve how the servers handle multiple simultaneous connections.
Node.js is a JavaScript runtime environment that combines several components: Google's V8 JavaScript engine, a single-threaded event loop, a platform-independent low-level API for I/O operations built on libuv, and a package manager for handling dependencies called npm. Interestingly enough, npm is currently the most significant open-source software registry globally.
The key design aspect of Node.js is that it performs non-blocking asynchronous I/O. An Input/Output operation can be anything that is not pure computation, for example, writing a file to disk, opening a connection to a database, or making a request to an external API.
Most online platforms are not CPU-intensive; they are data-intensive or I/O-intensive. They query databases and reply with processed data. In a multi-threaded server environment, at any given time, typically, there will be multiple threads that are blocked, waiting for an external data source to reply (whether it is a database, a persistence backend, or an external API). This means most server resources are locked and wasted by threads that aren't doing much.
On the other hand, Node.js is single-threaded and blocks on any CPU-bound operation, but it is multi-threaded and asynchronous for any I/O operation. As soon as the code makes an I/O request, this is delegated to the underlying asynchronous library libuv, and the event loop is free to continue its work. This allows Node.js servers to handle thousands of concurrent connections with a considerably small CPU footprint.
Because of the asynchronous nature of Node.js, developers need to have a good grasp on working with callbacks and promises. The good thing is that the typical user code of Node.js does not need to handle threads, which is a common source of bugs in languages that facilitate this (like C++ or Java).
Efficiency impact of server-side JavaScript
One of the typical sources of software development costs is the need to use different languages for backend, Frontend, and data manipulation. For example, a given platform could have its backend written in Java, its Frontend in PHP with a templating engine, use a relational database like MySQL for data storage and manipulation, and connect different modules via XML-based messaging. This means each layer of the architecture uses a foreign language, which adds complexity and causes the need to hire developers for each different technology.
Node.js allows running JavaScript on the backend. If the Frontend is some form of Web technology, it will also rely on JavaScript. Backend and Frontend can exchange information using JSON (JavaScript Object Notation), natively supported by JavaSCript. On top of that, non-relational databases like MongoDB store objects in JSON format and use JavaScript as a query language. In summary, all the layers of a platform's architecture could be built using just JavasScript as a programming language. There is a powerful impact on adopting JavaScript for server-side operations. For more information on this architecture approach, have a look at the MEAN stack here (although the "A" stands for "Angular" currently, React.js could be considered a better alternative).
Popular Node.js frameworks
According to StackOverflow's annual developer survey, JavaScript is currently the most used programming language globally. Over the years, this vast open-source community has created many powerful frameworks and libraries for building highly scalable asynchronous applications. This section will provide a brief list of some of the most popular ones.
Sails.js
Sails.js is an MVC (Model-View-Controller) application framework for node.js. Bundled with an ORM, it allows using any database. REST APIs and single-page apps (SPA) are auto-generated, with "blueprints" available to jumpstart development. Sails.js was inspired by Ruby-on-Rails "convention over configuration" and "scaffolding" principles. Sails.js intensively relies on code generation, which may not be appropriate for all scenarios. It offers native WebSockets support, among other modern features.
Express.js
Express presents itself as a "Fast, unopinionated, minimalist web framework for Node.js." It's one of the most popular app frameworks for Node.js out there. Express uses the "Chain of Responsibility" design pattern, using "middleware" functions that handle incoming HTTP requests. Many frameworks are, in fact, based on Express.js. Examples are Sails, Nest, and Kraken, among many others.
Express offers a minimal interface for building applications, adding Node.js the capability of dealing with routes and endpoints with little to no complexity.
Hapi
Its name derives from HTTP + API; Hapi is a simple and secure framework for building Node.js apps. Developed initially by Walmart to handle the massive amount of requests they received on Black Friday, its trademarks are scalability and security. Hapi core does not have any external code dependencies. Their development team enforces a lot of security best practices. Hapi was created by Eran Hammer, a known identity protocols author.
Because one of the main drivers of Hapi is security, they offer a set of official plugins so developers can avoid resorting to unverified npm libraries. Another security-related strong point is that Hapi natively integrates an authorization and authentication architecture.
Socket.io
Socket.io is a server-side library for WebSockets. If a WebSocket connection is unavailable, it will default to long-polling via HTTP, making it a reliable component for handling connections to the browser. Its features include "room" namespaces, multiplexing, binary buffers, etc. Interestingly, they offer client libraries for many other popular programming languages like Java, Python, and C++.
Pug
A very popular templating engine, Pug allows rendering dynamic content server-side. Pug seamlessly integrates with Express.js, as stated in this guide. It is inspired by HAML, another popular DRY ("Don't repeat yourself") templating library.
As a side note on server-side generated HTML pages, it may not always be the best architectural choice. Sometimes statically exporting pages to be served by CDN and keeping all dynamic code browser-side can positively impact scalability.
Nodemon
Nodemon is a utility for development that monitors the code for changes and automatically reloads as needed. More than 1.5 million projects use Nodemon worldwide.
Luxon
Luxon is a JavaScript library for working with times and dates. It is considered the evolution of the now-deprecated moment.js.
When to use Node.js
Given Node.js asynchronous I/O nature, it is an excellent choice for I/O bound apps like REST APIs that gather information from databases and external sources. Data Streaming apps, any Data-Intensive application, JSON APIs and web services, and servers for Single Page Apps.
The result is that Node.js may be discouraged for CPU-intensive applications. However, using workers threads, a Node.js application could spawn threads that run JavaScript in parallel.
Summary
JavaScript was born for the Web, specifically for making dynamic pages running on web browsers. After nearly two decades of being a language constraint to this role (and some unpopular attempts by different companies), the launch of Node.js liberated JavaScript to be also run server-side.
Node.js is a JavaScript runtime environment based on Google's V8 JavaScript engine. The main characteristic of Node.js is that it offers asynchronous I/O operations, launched from a single-thread process.
Under the hood, a key component of Node.js is the cross-platform asynchronous I/O library "libuv." This library is written in C language, and as they state on their website, "Node is libuv with a very well known client language." Its cross-platform nature allows each operating system to resolve the implementation of asynchronous I/O how it suits best, currently being supported in Windows, Linux and macOS.
One of the most popular application frameworks for Node.js is Express, allowing the development of minimalistic REST APIs by concatenating "middleware" functions in endpoint declarations.
A key aspect of using Node.js is enabling JavaScript across an application's entire stack. Using the same language for database (MongoDB), backend (Node.Js), Frontend (React.Js), and messaging (JSON) can make a significant impact on project costs and overall efficiency.
Is your development team looking to implement JavaScript server-side applications? We are Node.js experts as stated by TopDevelopers on their website; drop us a line!