Node JS

Node.js is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts.

Node.js runs the V8 JavaScript engine, the core of Google Chrome, outside of the browser. This allows Node.js to be very performant.

A Node.js app runs in a single process, without creating a new thread for every request. Node.js provides a set of asynchronous I/O primitives in its standard library that prevent JavaScript code from blocking and generally, libraries in Node.js are written using non-blocking paradigms, making blocking behavior the exception rather than the norm.

When Node.js performs an I/O operation, like reading from the network, accessing a database or the filesystem, instead of blocking the thread and wasting CPU cycles waiting, Node.js will resume the operations when the response comes back.

This allows Node.js to handle thousands of concurrent connections with a single server without introducing the burden of managing thread concurrency, which could be a significant source of bugs.

Node.js has a unique advantage because millions of frontend developers that write JavaScript for the browser are now able to write the server-side code in addition to the client-side code without the need to learn a completely different language.

In Node.js the new ECMAScript standards can be used without problems, as you don't have to wait for all your users to update their browsers - you are in charge of deciding which ECMAScript version to use by changing the Node.js version, and you can also enable specific experimental features by running Node.js with flags.

An Example Node.js Application

The most common example Hello World of Node.js is a web server:

const { createServer } = require('node:http');

const hostname = '127.0.0.1';
const port = 3000;

const server = createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

To run this snippet, save it as a server.js file and run node server.js in your terminal. If you use mjs version of the code, you should save it as a server.mjs file and run node server.mjs in your terminal.

This code first includes the Node.js http module.

Node.js has a fantastic standard library, including first-class support for networking.

The createServer() method of http creates a new HTTP server and returns it. The server is then set to listen on the specified port and host name. When the server is ready, the callback function is called, in this case informing us that the server is running.

Whenever a new request is received, the request event is called, providing two objects: a request (an http.IncomingMessage object) and a response (an http.ServerResponse object). Those two objects are essential to handle the HTTP call. The first provides the request details. In this simple example, this is not used, but you could access the request headers and request data.

The second is used to return data to the caller. In this case with:

res.statusCode = 200;

[...]

Differences between Node.js and the Browser

Both the browser and Node.js use JavaScript as their programming language. Still, building apps that run in the browser is completely different from building a Node.js application. Despite the fact that it's always JavaScript, there are some key differences that make the experience radically different.

From the perspective of a frontend developer who extensively uses JavaScript, Node.js apps bring with them a huge advantage: the comfort of programming everything - the frontend and the backend - in a single language.

In the browser, most of the time what you are doing is interacting with the DOM, or other Web Platform APIs like Cookies. Those do not exist in Node.js, of course. You don't have the document, window and all the other objects that are provided by the browser. And in the browser, we don't have all the nice APIs that Node.js provides through its modules, like the filesystem access functionality.

Another big difference is that in Node.js you control the environment. Unless you are building an open source application that anyone can deploy anywhere, you know which version of Node.js you will run the application on. Compared to the browser environment, where you don't get the luxury to choose what browser your visitors will use, this is very convenient.

This means that you can write all the modern ES2015+ JavaScript that your Node.js version supports. Since JavaScript moves so fast, but browsers can be a bit slow to upgrade, sometimes on the web you are stuck with using older JavaScript / ECMAScript releases. You can use Babel to transform your code to be ES5-compatible before shipping it to the browser, but in Node.js, you won't need that.

Another difference is that Node.js supports both the CommonJS and ES module systems (since Node.js v12), while in the browser, we are starting to see the ES Modules standard being implemented. In practice, this means that you can use both require() and import in Node.js, while you are limited to import in the browser.

The Node.js File System Module (fs)

(From https://www.w3schools.com/nodejs/nodejs_filesystem.asp)

The Node.js File System module (fs) provides a comprehensive set of methods for working with the file system on your computer. It allows you to perform file I/O operations in both synchronous and asynchronous ways.

Note: The File System module is a core Node.js module, so no installation is required.

Importing the File System Module

You can import the File System module using CommonJS require() or ES modules import syntax:

CommonJS (Default in Node.js)

const fs = require('fs');

ES Modules (Node.js 14+ with "type": "module" in package.json)

import fs from 'fs';
// Or for specific methods:
// import { readFile, writeFile } from 'fs/promises';

Promise-based API

Node.js provides promise-based versions of the File System API in the fs/promises namespace, which is recommended for modern applications:

// Using promises (Node.js 10.0.0+)
const fs = require('fs').promises;

// Or with destructuring
const { readFile, writeFile } = require('fs').promises;

// Or with ES modules
// import { readFile, writeFile } from 'fs/promises';

Reading Files

Node.js provides several methods to read files, including both callback-based and promise-based approaches.

The most common method is fs.readFile().

Note: Always handle errors when working with file operations to prevent your application from crashing.

Reading Files with Callbacks

Here's how to read a file using the traditional callback pattern. Say you write a text file called myfile.txt with contents:

This is the content of myfile.txt

Next, create a Node.js file that reads the text file, and return the content, with callbacks:

const fs = require('fs');

// Read file asynchronously with callback
fs.readFile('myfile.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file:', err);
    return;
  }
  console.log('File content:', data);
});

// For binary data (like images), omit the encoding
fs.readFile('image.png', (err, data) => {
  if (err) throw err;
  // data is a Buffer containing the file content
  console.log('Image size:', data.length, 'bytes');
});

Reading Files with Promises (Modern Approach)

Using fs.promises or util.promisify for cleaner async/await syntax. In the example we read a file with async/await

// Using fs.promises (Node.js 10.0.0+)
const fs = require('fs').promises;

async function readFileExample() {
  try {
    const data = await fs.readFile('myfile.txt', 'utf8');
    console.log('File content:', data);
  } catch (err) {
    console.error('Error reading file:', err);
  }
}

readFileExample();

// Or with util.promisify (Node.js 8.0.0+)
const { promisify } = require('util');
const readFileAsync = promisify(require('fs').readFile);

async function readWithPromisify() {
  try {
    const data = await readFileAsync('myfile.txt', 'utf8');
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

readWithPromisify();

Reading Files Synchronously

For simple scripts, you can use synchronous methods, but avoid them in production servers as they block the event loop:

Example: Reading a file synchronously

const fs = require('fs');

try {
  // Read file synchronously
  const data = fs.readFileSync('myfile.txt', 'utf8');
  console.log('File content:', data);
} catch (err) {
  console.error('Error reading file:', err);
}

Creating and Writing Files

Node.js provides several methods for creating and writing to files. Here are the most common approaches:


            


            


            


            


          


            


            


            


            


          


            


            


            


            


          


          


          


          


          


        


          


          


          


          


          


          


          


          


          


          


        

npm

npm is the standard package manager for Node.js.


npm installs, updates and manages downloads of dependencies of your project. Dependencies are pre-built pieces of code, such as libraries and packages, that your Node.js application needs to work.

Installing all dependencies

If a project has a package.json file, by running

npm install

it will install everything the project needs, in the node_modules folder, creating it if it's not existing already.

Installing a single package

You can also install a specific package by running

npm install <package-name>

Furthermore, since npm 5, this command adds <package-name> to the package.json file dependencies. Before version 5, you needed to add the flag --save.

Updating packages

Updating is also made easy, by running

npm update

npm will check all packages for a newer version that satisfies your versioning constraints.