Node.js

    0
    5
    « Back to Glossary Index

    What is Node.js?

    Node.js is an open-source, cross-platform runtime environment that allows JavaScript code to execute outside a web browser. Built on Google’s V8 engine, Node.js provides server-side objects for interacting with the file system and network, enabling JavaScript to power full-stack applications.

    Its event-driven, non-blocking I/O model means that operations such as disk and network access don’t block the main thread, making Node.js lightweight and well-suited for real-time, data-intensive applications.

    Node.js is not a programming language or framework—it is a runtime that extends JavaScript’s reach to servers, command-line tools, and IoT devices.

    How Node.js Works: History and architecture

    Node.js was introduced in 2009 by Ryan Dahl to enable server-side JavaScript. Traditional JavaScript engines run inside browsers like Chrome, Firefox, or Edge and provide objects such as window and document.

    Node.js repurposes Google’s V8 engine by embedding it in a C++ program. It exposes different APIs optimized for server-side development. Instead of browser-specific objects, Node.js provides modules for file system access, networking, and process control.

    Node.js key components

    • V8 engine – compiles JavaScript into efficient machine code. This engine delivers high performance and underpins features such as just-in-time compilation. Using V8 means Node.js can execute JavaScript at speeds comparable to languages like C++.
    • Libuv – a C library that abstracts asynchronous I/O operations and implements the event loop. Libuv handles tasks like file system calls, DNS queries, and network operations using underlying system threads.
    • Event loop – the central mechanism that processes callbacks and orchestrates asynchronous operations. The event loop allows Node.js to perform non-blocking I/O despite using a single JavaScript thread by offloading operations to the system kernel. Once asynchronous operations complete, corresponding callbacks are queued and executed in a series of phases.
    • Modules and package system – Node.js uses CommonJS modules via require() and exports to organize code into reusable files. The Node Package Manager (npm), which is installed with Node.js, hosts hundreds of thousands of packages that simplify tasks ranging from HTTP servers to database connectors. Packages are versioned and managed through the package.json file.

    Event-driven and non-blocking model

    Node.js’s defining feature is its event-driven architecture. In this design, logic responds to events rather than following a strict sequence.

    Node.js relies on a single-threaded event loop that monitors events and invokes callback functions when those events occur.

    Operations like file reads or network requests are initiated and then the runtime continues processing other tasks rather than waiting; when the operation finishes, a callback is triggered to handle the result. This non-blocking behaviour allows Node.js to manage many concurrent connections efficiently.

    Internally, the event loop cycles through phases to process callbacks:

    • Timers – execute callbacks scheduled by setTimeout() or setInterval() when their time threshold is reached.
    • Pending callbacks – processes I/O callbacks deferred to the next loop iteration.
    • Idle/prepare – internal phase used by Node.js.
    • Poll – retrieves new I/O events and executes callbacks (e.g., file system, network); it may block if there are no pending timers.
    • Check – executes callbacks scheduled by setImmediate().
    • Close callbacks – handles closure events like closing network sockets.

    Running JavaScript outside the browser

    Node.js differs from browsers not only in its event loop but also in the environment it exposes. In browsers, the global object is window; in Node.js, it is called global.

    Node.js scripts can access modules like fs for file system operations, http for creating servers, and process for environment variables and runtime information.

    These modules are part of Node.js’s standard library and allow developers to build full server applications using only JavaScript. Node.js is cross-platform and runs on Windows, macOS, Linux, and other operating systems.

    Why is Node.js important?

    1. Full-stack JavaScript and developer productivity

    One major benefit of Node.js is that it enables full-stack development using a single language. Traditionally, developers wrote client-side code in JavaScript and server-side code in another language (PHP, Ruby, Java, etc.).

    With Node.js, developers can use JavaScript on both ends, reducing context switching and making it easier for teams to share code between the frontend and back end. This unified language approach simplifies student education and speeds up project development.

    2. Asynchronous scalability and performance

    Node.js’s event-driven, non-blocking I/O model makes it highly scalable and efficient for network applications. Instead of spawning a new thread for each connection like traditional multi-threaded servers, Node.js handles many connections within a single process and thread.

    Node’s event-driven architecture enables it to handle multiple concurrent requests without slowing down or consuming significant memory. This lightweight concurrency model avoids deadlocks and reduces context switching compared with multi-threaded frameworks.

    3. Ecosystem and community

    Node.js comes bundled with npm, a package manager containing a large registry of community-contributed modules. These packages cover everything from creating web servers (Express.js) to database connectors, authentication modules, and developer tools.

    The availability of these packages accelerates experimentation and learning for students learning Node.js. Node.js’s open-source nature fosters a large and active community.

    Major companies (Netflix, LinkedIn, PayPal) use Node.js in production. This community involvement ensures that bugs are fixed quickly, new features are introduced, and the ecosystem remains vibrant.

    4. Versatility across domains

    Node.js is used in a broad range of domains beyond simple web servers. Node.js is well-suited for streaming services, real-time chat applications, single-page applications (SPAs), microservices, IoT devices, and proxy servers.

    Its non-blocking architecture allows it to manage many simultaneous device connections, making it ideal for IoT scenarios. It also plays a central role in modern development pipelines as a scripting environment for building tools and automating tasks.

    Node.js examples and use cases

    1. Creating a simple HTTP server

    One of the most common tasks in Node.js is building a server. The built-in http module makes this easy:

    // simple HTTP server responding with "Hello, World!"
    const http = require('http');
    
    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello, World!\n');
    });
    
    server.listen(3000, () => {
      console.log('Server running at http://localhost:3000/');
    });

    This example illustrates how an HTTP server can be created with just a few lines of JavaScript.

    When a request arrives, the callback provided to createServer is triggered—Node.js’s event loop listens for connections and invokes the callback for each request.

    2. Asynchronous file reading

    The fs module provides asynchronous methods that don’t block the event loop. Reading a file asynchronously looks like this:

    const fs = require('fs');
    
    fs.readFile('example.txt', 'utf8', (err, data) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log('File content:', data);
    });
    
    console.log('Reading file...');

    The fs.readFile function kicks off an I/O operation and returns immediately; the callback prints the file’s contents once reading completes.

    Using asynchronous operations ensures that other tasks continue executing while Node.js waits for the file I/O.

    3. EventEmitter for custom events

    Node.js’s EventEmitter allows developers to define custom events and listeners.

    const EventEmitter = require('events');
    
    class MyEmitter extends EventEmitter {}
    
    const myEmitter = new MyEmitter();
    
    // register a listener for the custom event
    a
    myEmitter.on('dataReceived', (data) => {
      console.log('Data received:', data);
    });
    
    // emit events with accompanying data
    myEmitter.emit('dataReceived', { message: 'Hello from event emitter!' });
    myEmitter.emit('dataReceived', { message: 'Another message!' });

    In this code, the on method registers a callback, and emit triggers the event. Event emitters form the basis for many Node.js libraries and frameworks (e.g., streams, HTTP servers) and illustrate the event-driven philosophy.

    What is Node.js used for?

    Node.js powers a wide variety of software:

    • Streaming services – Node.js’s ability to handle concurrent connections with low latency makes it popular for video and audio streaming platforms.
    • Real-time communication – chat applications and collaboration tools rely on Node’s event-driven model to manage WebSocket connections and broadcast messages simultaneously.
    • Single-page applications (SPAs) – SPAs require frequent communication between the client and server; Node.js facilitates this by serving as a fast, lightweight backend.
    • Microservices – Node.js works well for microservices architectures because it can handle many small services using minimal resources.
    • Internet of Things (IoT) – Node.js manages numerous device connections and processes sensor data efficiently due to its non-blocking I/O model.
    • Proxy servers and tools – Node.js can act as a proxy or build network utilities; its modularity makes it suitable for command-line tools and build scripts.

    How Node.js runtime works – step-by-step breakdown

    Although Node.js runs in a single thread, it can handle many operations concurrently thanks to its event loop and thread pool. Here is a high-level breakdown of what happens when a Node.js server receives a request:

    1. Initialization – When the program starts, Node.js sets up the event loop and loads the initial script. The script can schedule timers, start network servers or initiate I/O operations.
    2. Receive request – A client request arrives via the operating system’s networking stack and is placed in an internal event queue managed by libuv.
    3. Execute callback – When the event loop reaches the poll phase and the poll queue contains an event, Node.js executes the associated callback (e.g., the function passed to http.createServer). Inside this callback, the application can read request data, access databases or perform other operations.
    4. Perform I/O – If the handler initiates an asynchronous I/O operation (such as reading from disk or querying a database), Node.js delegates the operation to the OS. The event loop continues processing other events and does not block.
    5. Queue callback – Once the OS completes the I/O, libuv queues the callback in the appropriate phase (often the poll phase), where Node.js executes it and sends the response.
    6. Repeat – The event loop repeats this cycle until there are no more pending events or timers, at which point Node.js shuts down gracefully.

    Related concepts

    To fully understand Node.js, it helps to be familiar with these related topics:

    • Asynchronous programming – The programming model where tasks run concurrently without blocking. Node.js leverages callbacks, Promises, and async/await for asynchronous control flow.
    • Event loop – The core mechanism that processes callbacks in Node.js and browsers. Understanding the event loop phases helps debug timing issues.
    • Non-blocking I/O – I/O operations that don’t block the main thread. Node.js offloads such operations to the OS through libuv and processes callbacks when they complete.
    • Modules and packages – The CommonJS module system (require() and exports) and npm’s package management allow code reuse and modular architecture.
    • Express.js – A minimal web framework built on Node.js’s http module. It simplifies routing, middleware, and templating for web applications.
    « Back to Glossary Index