Skip to Main Content

Node.js

JavaScript was initially developed for client-side scripting within the browser. Thanks to the <script> tag, developers could embed code to manipulate data and behavior in web applications. Millions of websites use JavaScript, making it one of the most well-liked programming languages for web development.

However, the language could not execute server-side code, meaning web applications had to use a different programming language on the back end. This fact continued to be the state of web development until May 2009, when Node.js emerged.

Node.js is a runtime environment that allows JavaScript code to run outside a browser. It began with software developer Ryan Dahl's dissatisfaction with the state-of-the-art web tools for managing networking operations. He decided to use Google's V8, a powerful JavaScript engine, to conduct networking-related activities on the server. These days, Node.js is used for various purposes, some of which we'll discuss on this page.

Node.js

What is Node.js?

Node.js is a cross-platform, single-threaded, open-source runtime environment that runs JavaScript applications outside the client's browser. It is written in C / C++ and is built on top of Google's V8 JavaScript engine to expose a set of libraries to JavaScript. The Chromium project from Google initially developed V8 to run for the Chrome browser and Chromium-based applications. At its core, V8 is a powerful virtual machine that compiles JavaScript to native machine code before its execution to achieve runtime performance.

Node.js was first presented by American software engineer Ryan Dahl in 2009 at the annual European JSConf to offer networking applications a non-blocking input / output (I / O) architecture. He wanted to work in an environment that could handle different networking tasks simultaneously without sacrificing performance.

Dahl questioned how traditional server applications used to perform I / Orelated jobs. Before Node.js, a typical server would block the program while waiting for a response after being asked to complete an I / O task (for example, querying the database). Initial web application technologies attempted to avoid this issue by spinning up threads for requests. A different thread would handle each request to minimize wait time for clients.

However, threads were not free. Each thread execution stack required context switching and additional memory. Also, they could still block while performing I / O operations. Dahl believed he could leverage the power of the V8 JavaScript engine to design a fast, single-threaded, cross-platform environment that would use an event-driven and non-blocking I / O architecture. And Node.js was born!

We'll unpack each of the descriptors of Node.js in a later section of this page. But for now, we'll note that Node.js allows developers to write applications that concurrently execute most I / O and JavaScript code operations without blocking. This non-blocking I / O model is at the core of Node.js’s strength.

Dahl drove the initial development and maintenance of Node.js. Being an open-source project, Node.js was later sponsored by Joyent, a cloud computing provider currently owned by Samsung. Joyent had previously been an active sponsor of Ruby on Rails before they decided to move on to Node.js. The cloud company believed this could help them speed up the delivery of new features and services in their cloud. Several organizations rely on Node.js to build web APIs, real-time applications, data streaming, IoT, Chatbots, server-side proxies, scripting, automation, etc.

One of the main factors of Node.js’s popularity has been its software library registry, npm. The Node.js package manager provides developers a mechanism for sharing and using reusable code packages to solve the most common software problems. Node.js's wide adoption is driven by an active open-source community that has developed many Node.js resources, conferences, and frameworks. Node.js frameworks help to create unique capabilities for Node.js and expedite the development of Node.js applications. These frameworks include Express.js, Sails.js, Koa.js, Meteor.js, socket.io, Loopback.js, and many more.

Another factor contributing to Node.js’s popularity is the ability to support the same language across the stack. Thanks to Node.js, developers can now use JavaScript client side and server side. For example, you can run a web server using a Node.js framework like Express.js and render the front end using a JavaScript framework like React. It's even possible to use some Node.js packages in the front end. Furthermore, data can be transferred across the stack using a unified data format, JSON. And solutions can achieve all these things without ever leaving the JavaScript ecosystem!

Node.js

What is Node.js used for?

There are many advantages to using Node.js:

  • Language sharing across the stack: Node.js makes it possible to use JavaScript in front-end and back-end development. This differentiates it from other languages and frameworks such as Python, Java, or Ruby on Rails. Developers can also seamlessly exchange code between client and server applications.

  • Rapid software development: Node.js is based on JavaScript, which is relatively easy to learn. The JavaScript language is already accessible to several front-end developers as it has been around for over two decades. Furthermore, bootstrapping an API on Node.js only takes a few minutes. Node.js is also a good choice for prototyping solutions as it enables quick experimentation.

  • Scalability: Node.js uses an event-driven, non-blocking I / O architecture to remain an efficient and lightweight environment for running real-time applications spread across distributed devices.

  • Large active community: Node.js is part of the OpenJS Foundation, whose mission is to promote ongoing development and encourage broad adoption of JavaScript-based technologies. Node.js's open-source community is constantly working toward making sure Node.js, and many other resources, are available.

  • Massive ecosystem: Node.js has built-in support for package management through the Node Package Manager (npm). This registry gives access to reusable and publicly accessible packaged modules. It has become the most significant software library registry to date.

  • Seamless data transfer with JSON: Other back-end languages like Java and Python can use JSON format to interchange data. However, Node.js can use this data transfer standard without converting between binary models, as JSON is a subset of JavaScript.

  • Access to TypeScript: JavaScript is, by nature, a dynamically and weakly typed language; i.e., data types and their related errors are only detected at runtime. This fact can lead to errors in production that a language with stricter type checking could have caught earlier. Type checking is one of the problems TypeScript aims to solve. It provides syntactic sugar around JavaScript with optional features such as typing and object-oriented programming. The advent of TypeScript delivers a clear advantage to developers as they can better tailor their applications to their specific needs. Finally, using a statically typed language makes code refactoring much easier due to better IDE support.

Although Node.js offers many advantages, there are still occasions where there may be better tools for the problem to be solved.

  • Heavy server-side computation and processing: Node.js naturally excels at performing small tasks fast and I / O operations that can run asynchronously. However, its main thread struggles to process CPU-intensive operations efficiently. If your server instance needs to run heavy computations, Node.js will first allocate all the available CPU resources to process them. This can result in other incoming requests being queued for a considerable amount of time and cause a performance bottleneck. Node.js attempted to resolve this issue by introducing multithreading through the worker threads module. This module enables multiple instances of Node.js in a single process to carry out CPU-intensive work. Yet, spawning too many worker threads will consume significant host resources.

  • Immature tooling: Although there are many mature and stable Node.js modules in npm, there are also tools with poor documentation, poor quality, or significant security vulnerabilities. So at times, finding the best solution for the problem you're trying to solve might be challenging. There is also the risk that your application might become a messy codebase with multiple dependencies that need high maintenance. However, adhering to good development standards and regular code hygiene tasks will mitigate some of these disadvantages.

Now that we know about the advantages and disadvantages of Node.js, here are the types of applications this tool is suitable for.

Web APIs

Node.js is a good candidate for applications that need to expose data from databases over HTTP. It uses JSON to seamlessly serialize data across the server, client, and database. It is especially beneficial for applications with a NoSQL database such as MongoDB.

Data Streaming

Traditional web technologies handle HTTP requests and responses as isolated events instead of streams. Node.js can, on the other hand, efficiently process data in chunks thanks to its asynchronous, non-blocking I / O model. For example, processing files when they're still being uploaded is possible. Hence, Node is well suited for applications that do high-volume streaming or need to proxy data between multiple sources.

Chat Applications

Node.js is well suited to handle heavy I / O operations because it uses an event-driven and asynchronous architecture. It's much easier to develop highly efficient real-time applications with this tool. Node.js' Socket.IO library enables bidirectional, event-based, real-time communication between the server and the browser. And you can boot up a chat application with only a few lines of code.

Scripting

Node.js has many libraries, making writing fast and efficient command-line applications relatively easy. As such, developers, who may need to become more familiar with languages like Bash, can still use JavaScript to write automation scripts.

Embedded Systems

Node.js is becoming famous for hardware programming, and it offers libraries that developers can leverage to build Internet of Things applications. There are also embedded systems that directly support Node.js and JavaScript out of the box, e.g., Raspberry Pi.

Node.js

Demonstration

Asynchronous Programming

To understand how JavaScript achieves asynchronous processing, we first need to grasp the notion of functions as first-class citizens.

JavaScript treats functions as first-class citizens. Functions are objects; hence, they can be assigned to variables, passed in as arguments to other functions, and returned by functions. JavaScript leverages the passing of functions as arguments to achieve asynchronous processing.

In a traditional web platform, an application blocks when it needs to process I / O operations, e.g., reading from a database. Any other operation has to wait until I / O processing has finished. However, Node.js makes it possible for applications to have non-blocking I / O processing. Thanks to its asynchronous nature, a Node.js application can still process other operations as they come.

We'll illustrate both blocking and non-blocking I / O with two simple examples. Let's assume we have a file named "random-file.md" with the following content:

File can be read synchronously
File can be read asynchronously

Here is a code example to process the file content in a synchronous fashion:

const fs = require('fs');

console.log('About to read file content');
try {
    let content = fs.readFileSync('random-file.md', 'utf-8');
    console.log(content);
    console.log('Done reading file');
} catch (err) {
    console.log(err);
}

console.log('Node.js is based on JS.');

Source: https://gist.github.com/charlenetshos/733f4b96c4a38d89b55279bbbeb123cb

In the above code snippet, Node.js will be blocked until the file reading has been completed. So the console will log the following output:

About to read file content
File can be read synchronously
File can be read asynchronously
Done reading file
Node.js is based on JS

Now, let's rewrite the example to process the file asynchronously.

const fs = require('fs');

console.log('About to read file content');
fs.readFile('file.md', 'utf-8', function (err, content) {
    if (err) {
        return console.log(err);
    }
    console.log(content);
    console.log('Done reading file');
});
console.log('Node.js is based on JS');

Source: https://gist.github.com/charlenetshos/9316c378ae28bf57ba2ee04bcf6d21c7

If you run the above code snippet, you'll notice that the console will log "Node.js is based on JS" before the file content.

About to read file content
Node.js is based on JS
File can be read synchronously
File can be read asynchronously
Done reading file

That's because Node.js is not waiting for file reading to complete before processing other operations.

Event Loop

The event loop runs tasks in a single main thread and continuously collects polls and callbacks from the event queue, one at a time. It typically delegates blocking I / O tasks to a threads pool, and each task has a callback function with operations that need to happen when the I / O task is done.

So in a typical Node.js server, the event loop gets multiple requests and processes them one at a time as they come out of the event queue. Each request represents an event and has a callback function responsible for sharing the response with the client once the request has finished its course. The event loop executes operations for each event and delegates I / O-intensive tasks to the threads pool. Each I / O task has its callback. The event loop goes through each callback from the event queue. When it gets to the callback to return an HTTP response, it executes it, and the client receives a response.

Hence a Node.js server can run on a single thread.


Node.js

FAQs

  • Is Node.js a language or framework?
  • Why is Node.js fast?
  • What is a promise in JavaScript?
  • What is Node.js I / O?
  • Do I have to use TypeScript for a Node.js application?
  • What is the difference between Node.js and Ruby on Rails?
Node.js

Terminology

API: An interface for accessing external data or functionality.

Function: A function is a block of code that performs a specific task, and can be called or invoked by other code in the program.

I / O operation: An operation that accepts an input and generates an output.

Object: A collection of properties associated with a single entity. A property represents an association between a key (name of the property) and a value. A value can be a number, string, object, function (method), etc.

Runtime environment: An environment that provides all the necessary functionality for a program to run within a platform.

Thread: A small set of instructions that the CPU can schedule and run independently of the parent process.

Event loop: The event loop is Node.js main thread that waits for events to occur and processes them one after another.

Case Studies

Helping AMA healthcare workers get course credit faster

Let’s start a conversation

Let's shape your insights into experience-led data products together.