Node.js is an open-source, cross-platform JavaScript runtime environment. It is a popular tool for almost any kind of project! Node.js runs the V8 JavaScript engine, the core of Google Chrome, outside of the browser, allowing Node.js to be very performant.
Node.js runs in a single process without creating a new thread for every request. It provides a set of asynchronous I/O primitives in its standard library that prevent JavaScript code from blocking. 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 who write JavaScript for the browser can now write the server-side code in addition to the client-side code without needing 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.
The most common example of a "Hello World" application in Node.js is a web server. Below is a simple example:
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.
1. Including the HTTP Module
const { createServer } = require('node:http');
Node.js has a fantastic standard library, including first-class support for networking. Here, we include the HTTP module.
2. Defining Hostname and Port
const hostname = '127.0.0.1';
const port = 3000;
We define the hostname and port where the server will listen for requests.
3. Creating the Server
const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
The `createServer()` method of the HTTP module creates a new HTTP server and returns it. The server listens for incoming requests and provides a callback function to handle the requests.
4. Starting the Server
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
The server is set to listen on the specified port and hostname. When the server is ready, the callback function is called, informing us that the server is running.
Whenever a new request is received, the callback function is called, providing two objects: a request (an `http.IncomingMessage` object) and a response (an `http.ServerResponse` object). These two objects are essential for handling the HTTP call.
1. Request Details
The `request` object provides the request details. In this simple example, this is not used, but you could access the request headers and request data.
2. Response
The `response` object is used to return data to the caller.
res.statusCode = 200;
We set the `statusCode` property to `200` to indicate a successful response.
res.setHeader('Content-Type', 'text/plain');
We set the `Content-Type` header to `text/plain`.
res.end('Hello World\n');
We close the response, adding the content as an argument to `end()`.
This is a basic example of creating an HTTP server in Node.js. From here, you can expand your server to handle different routes, serve static files, interact with databases, and more. Node.js's non-blocking I/O and single-threaded event loop make it a powerful choice for building scalable network applications.