Top Node.js Interview Questions and Answers

author image Hirely
at 08 Jan, 2025

Question: What is the difference between process.nextTick() and setImmediate() in Node.js?

Answer:

Both process.nextTick() and setImmediate() are used to schedule callbacks to be executed asynchronously in Node.js, but they differ in when and how they are executed within the event loop. Here’s a breakdown of the differences:

1. Execution Timing:

  • process.nextTick():

    • The callback function passed to process.nextTick() is executed immediately after the current operation completes and before any I/O events or timers in the event loop.
    • This means that process.nextTick() runs before the I/O events (like timers or I/O callbacks) in the event loop, and before any other queued microtasks or callbacks. This makes it a high priority compared to other asynchronous callbacks.
    • It is typically used when you need to ensure that certain code runs as soon as possible, but after the current operation, but before I/O or timers.
  • setImmediate():

    • The callback passed to setImmediate() is executed on the next iteration of the event loop, specifically after I/O events (like timers and file system operations) have been processed but before setTimeout or setInterval callbacks are triggered.
    • It is designed to be used for tasks that should be executed after the current event loop cycle has finished, but not as urgently as process.nextTick().

2. Priority in the Event Loop:

  • process.nextTick():

    • Higher priority: Executes before any other I/O, timers, or setImmediate() callbacks. If there are multiple process.nextTick() calls, they are executed in the order they are queued before the event loop continues with its other tasks.
    • If too many process.nextTick() callbacks are scheduled, it can block the event loop, leading to potential performance issues (as it prevents the event loop from progressing).
  • setImmediate():

    • Lower priority: Executes after the current event loop phase (I/O callbacks), but before timers (setTimeout, setInterval). The callback will be placed in the “check” phase of the event loop.

3. Use Cases:

  • process.nextTick():

    • Use process.nextTick() when you need to run code immediately after the current operation and ensure that no other I/O or asynchronous operations interrupt it.
    • Common use cases include:
      • Ensuring that code runs before any I/O events.
      • Handling errors in synchronous code that should be caught right after the current task.
  • setImmediate():

    • Use setImmediate() when you want to run code as soon as the event loop has completed the current phase of execution.
    • It’s commonly used for tasks that should be deferred until after the current operation has finished, such as handling an event or completing a process that doesn’t need to be handled immediately.
    • You could use it when you’re processing a task asynchronously and need to yield back to the event loop for I/O processing.

4. Example:

// Using process.nextTick()
process.nextTick(() => {
    console.log('nextTick callback');
});

// Using setImmediate()
setImmediate(() => {
    console.log('Immediate callback');
});

// Output:
// nextTick callback
// Immediate callback

In this example, process.nextTick() will execute first, even though setImmediate() appears later. This is because process.nextTick() has a higher priority and executes before I/O operations, timers, and setImmediate().

5. Behavioral Example:

console.log("Start");

process.nextTick(() => {
    console.log("nextTick 1");
});

setImmediate(() => {
    console.log("Immediate 1");
});

process.nextTick(() => {
    console.log("nextTick 2");
});

setImmediate(() => {
    console.log("Immediate 2");
});

console.log("End");

Output:

Start
End
nextTick 1
nextTick 2
Immediate 1
Immediate 2

Here’s why this happens:

  • The “Start” and “End” log statements are executed synchronously.
  • process.nextTick() callbacks are executed before the setImmediate() callbacks, and they also have a higher priority, so nextTick 1 and nextTick 2 are logged first.
  • After the current operation completes, setImmediate() callbacks are executed in the next event loop cycle, which results in the logging of Immediate 1 and Immediate 2.

6. Key Differences in Summary:

Featureprocess.nextTick()setImmediate()
Execution TimingExecutes after the current operation, before I/O and timersExecutes on the next iteration of the event loop, after I/O events
PriorityHigher priority (before I/O callbacks)Lower priority (after I/O callbacks)
Use CaseUse for operations that need to execute immediately after the current operationUse for tasks that should run after the current operation completes but are less urgent
Blocking PotentialCan block the event loop if overusedLess likely to block the event loop, since it’s queued later
Event Loop PhaseRuns before I/O, timers, or setImmediate() callbacksRuns after I/O callbacks, before timers (setTimeout, setInterval)

Conclusion:

  • process.nextTick() is ideal for executing code immediately after the current operation, but it has a higher priority and can block the event loop if overused.
  • setImmediate() is used for deferring execution of a callback until the next iteration of the event loop, allowing I/O and other tasks to be processed first.

Understanding the timing and priority differences between these two functions is essential for writing efficient and non-blocking Node.js applications.

Question: What are the key modules in Node.js?

Answer:

Node.js provides a rich set of built-in modules that are essential for various common tasks like file system operations, networking, cryptography, data streaming, and more. These modules are included by default, meaning you do not need to install them manually. Here are some of the key modules in Node.js:

1. HTTP (http)

  • The http module is one of the core modules in Node.js that allows you to create web servers and handle HTTP requests and responses.
  • Use case: Building web servers, APIs, or handling HTTP requests.
  • Example:
    const http = require('http');
    
    const server = http.createServer((req, res) => {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Hello, Node.js!');
    });
    
    server.listen(3000, () => {
        console.log('Server running at http://localhost:3000');
    });

2. File System (fs)

  • The fs module allows you to interact with the file system by reading from and writing to files, creating directories, and more.
  • Use case: Reading files, writing files, file manipulation.
  • Example:
    const fs = require('fs');
    
    // Reading a file asynchronously
    fs.readFile('example.txt', 'utf8', (err, data) => {
        if (err) throw err;
        console.log(data);
    });
    
    // Writing to a file
    fs.writeFile('output.txt', 'Hello, world!', (err) => {
        if (err) throw err;
        console.log('File has been written!');
    });

3. Path (path)

  • The path module provides utilities for working with file and directory paths in a platform-independent manner.
  • Use case: Manipulating file and directory paths.
  • Example:
    const path = require('path');
    
    const filePath = '/usr/local/bin';
    const baseName = path.basename(filePath);  // 'bin'
    const dirName = path.dirname(filePath);    // '/usr/local'
    const extName = path.extname('file.txt');  // '.txt'
    
    console.log(baseName, dirName, extName);

4. Events (events)

  • The events module provides an event-driven architecture and allows you to handle events and listeners. This is particularly useful for handling asynchronous operations.
  • Use case: Creating custom event-driven systems.
  • Example:
    const EventEmitter = require('events');
    const emitter = new EventEmitter();
    
    // Registering an event listener
    emitter.on('greet', () => {
        console.log('Hello, EventEmitter!');
    });
    
    // Emitting the event
    emitter.emit('greet');

5. Stream (stream)

  • The stream module provides APIs for dealing with streaming data. This is important for handling large files or data that comes in chunks, such as network requests.
  • Use case: Reading and writing large files, handling real-time data.
  • Example:
    const fs = require('fs');
    const readableStream = fs.createReadStream('input.txt');
    const writableStream = fs.createWriteStream('output.txt');
    
    readableStream.pipe(writableStream);

6. OS (os)

  • The os module provides information about the operating system, such as memory usage, platform, CPU architecture, etc.
  • Use case: Getting system-level information.
  • Example:
    const os = require('os');
    
    console.log('OS Platform:', os.platform()); // 'darwin', 'win32', 'linux'
    console.log('Total Memory:', os.totalmem());
    console.log('CPU Info:', os.cpus());

7. URL (url)

  • The url module provides utilities for URL resolution and parsing. It helps in working with URLs, extracting their components, and resolving relative URLs.
  • Use case: Parsing URLs, constructing URLs from components.
  • Example:
    const url = require('url');
    
    const parsedUrl = url.parse('https://www.example.com/path?name=value');
    console.log(parsedUrl.hostname); // 'www.example.com'
    console.log(parsedUrl.pathname); // '/path'

8. Crypto (crypto)

  • The crypto module provides cryptographic functionality, including hashing, encryption, and decryption.
  • Use case: Performing cryptographic operations like hashing passwords, generating tokens.
  • Example:
    const crypto = require('crypto');
    
    // Hashing a string using SHA-256
    const hash = crypto.createHash('sha256');
    hash.update('Hello, Node.js');
    console.log(hash.digest('hex'));

9. Cluster (cluster)

  • The cluster module allows you to create child processes (workers) that can share server ports. This is useful for scaling Node.js applications and making use of multi-core systems.
  • Use case: Scaling Node.js applications to handle more traffic.
  • Example:
    const cluster = require('cluster');
    const http = require('http');
    const numCPUs = require('os').cpus().length;
    
    if (cluster.isMaster) {
        // Fork workers
        for (let i = 0; i < numCPUs; i++) {
            cluster.fork();
        }
    
        cluster.on('exit', (worker, code, signal) => {
            console.log(`Worker ${worker.process.pid} died`);
        });
    } else {
        // Workers share the same server port
        http.createServer((req, res) => {
            res.writeHead(200);
            res.end('Hello from worker ' + process.pid);
        }).listen(8000);
    }

10. Child Process (child_process)

  • The child_process module allows you to spawn new processes, run shell commands, and interact with them.
  • Use case: Running shell commands or spawning new processes.
  • Example:
    const { exec } = require('child_process');
    
    exec('ls', (error, stdout, stderr) => {
        if (error) {
            console.error(`exec error: ${error}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
        console.error(`stderr: ${stderr}`);
    });

11. Timer (timers)

  • The timers module is used for setting and managing timers in Node.js, such as setTimeout(), setInterval(), and clearTimeout().
  • Use case: Deferring execution of code after a specified time or interval.
  • Example:
    setTimeout(() => {
        console.log('Executed after 2 seconds');
    }, 2000);

12. DNS (dns)

  • The dns module provides functions to perform DNS lookup and resolve hostnames.
  • Use case: Resolving domain names or working with DNS servers.
  • Example:
    const dns = require('dns');
    
    dns.lookup('www.example.com', (err, address, family) => {
        if (err) throw err;
        console.log('Address: ' + address);
        console.log('Family: ' + family);
    });

13. Process (process)

  • The process module provides information about the current Node.js process, including environment variables, exit codes, and command-line arguments.
  • Use case: Managing the Node.js process and interacting with system environment variables.
  • Example:
    console.log('Node.js Version:', process.version);
    console.log('Process ID:', process.pid);

Conclusion:

Node.js includes a wide range of built-in modules that are essential for creating scalable, performant, and feature-rich applications. Some of the key modules you will frequently use are http, fs, path, events, and stream, among others. These modules cover a wide variety of functionality, from handling HTTP requests to interacting with the file system, performing cryptographic operations, and working with child processes. Understanding and using these core modules efficiently is crucial for building robust Node.js applications.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as Node.js interview questions, Node.js interview experiences, and details about various Node.js job positions. Click here to check it out.

Related Posts

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now