interview

Top nodejs questions asked in interview (2024)

30 min read
#interview

What is Node.js?

Node.js is an open-source server side runtime environment built on Chrome's V8 JavaScript engine. It provides an event driven, non-blocking (asynchronous) I/O and cross-platform runtime environment for building highly scalable server-side applications using JavaScript.

Node.js is similar in design to, and influenced by, systems like Ruby's Event Machine and Python's Twisted. Node.js takes the event model a bit further. It presents an event loop as a runtime construct instead of as a library. In other systems, there is always a blocking call to start the event-loop. Typically, behavior is defined through callbacks at the beginning of a script, and at the end a server is started through a blocking call like EventMachine::run(). In Node.js, there is no such start-the-event-loop call. Node.js simply enters the event loop after executing the input script. Node.js exits the event loop when there are no more callbacks to perform. This behavior is like browser JavaScript — the event loop is hidden from the user


How does Node.js work?

A Node.js application creates a single thread on its invocation. Whenever Node.js receives a request, it first completes its processing before moving on to the next request.

Node.js works asynchronously by using the event loop and callback functions, to handle multiple requests coming in parallel. An Event Loop is a functionality which handles and processes all your external events and just converts them to a callback function. It invokes all the event handlers at a proper time. Thus, lots of work is done on the back-end, while processing a single request, so that the new incoming request doesn't have to wait if the processing is not complete.

While processing a request, Node.js attaches a callback function to it and moves it to the back-end. Now, whenever its response is ready, an event is called which triggers the associated callback function to send this response.


What is node.js used for?

  • Node.js is usually used for non-blocking and event-driven servers.

  • This makes it great for building things like static file servers, web application frameworks, REST APIs, messaging middleware, real-time services (chat, games, etc), command-line applications, browser games, and anything else that isn’t CPU intensive or doesn’t require long processing times.

  • Amongst those use-cases, web applications are the most commonly used by developers.


What are the core modules of Node.js?

Node.js has a set of core modules that are part of the platform and come with the Node.js installation. These modules can be loaded into the program by using the require function.

The following table lists some of the important core modules in Node.js and there uses

  • assert: Provides a set of assertion tests
  • buffer: To handle binary data
  • child_process: To run a child process
  • cluster: To split a single Node process into multiple processes
  • crypto: To handle OpenSSL cryptographic functions
  • dgram: Provides implementation of UDP datagram sockets
  • dns: To do DNS lookups and name resolution functions
  • domain: Deprecated. To handle unhandled errors
  • events: To handle events
  • fs: To handle the file system
  • http: To make Node.js act as an HTTP server
  • https: To make Node.js act as an HTTPS server.
  • net: To create servers and clients
  • os: Provides information about the operation system
  • path: To handle file paths
  • querystring: To handle URL query strings
  • readline: To handle readable streams one line at the time
  • stream: To handle streaming data
  • string_decoder: To decode buffer objects into strings
  • timers: To execute a function after a given number of milliseconds
  • tls: To implement TLS and SSL protocols
  • tty: Provides classes used by a text terminal
  • url: To parse URL strings
  • util: To access utility functions
  • v8: To access information about V8 (the JavaScript engine)
  • vm: To compile JavaScript code in a virtual machine
  • zlib: To compress or decompress files

What are the global objects of Node.js?

Node.js Global Objects are the objects that are available in all modules. Global Objects are built-in objects that are part of the JavaScript and can be used directly in the application without importing any particular module.

These objects are modules, functions, strings and object itself as explained below.

  1. global:

It is a global namespace. Defining a variable within this namespace makes it globally accessible.

var myvar;
  1. process:

It is an inbuilt global object that is an instance of EventEmitter used to get information on current process. It can also be accessed using require() explicitly.

  1. console:

It is an inbuilt global object used to print to stdout and stderr.

console.log("Hello World");
  1. setTimeout(), clearTimeout(), setInterval(), clearInterval():

The built-in timer functions are globals

function printHello() {
   console.log( "Hello, World!");
}
// Now call above function after 2 seconds
var timeoutObj = setTimeout(printHello, 2000);
  1. __dirname:

It is a string. It specifies the name of the directory that currently contains the code.

console.log(__dirname);
  1. __filename:

It specifies the filename of the code being executed. This is the resolved absolute path of this code file. The value inside a module is the path to that module file.

console.log(__filename);

What is v8 engine?

V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and in Node.js, among others. It implements ECMAScript and WebAssembly, and runs on Windows 7 or later, macOS 10.12+, and Linux systems that use x64, IA-32, ARM, or MIPS processors. V8 can run standalone, or can be embedded into any C++ application.

This V8 engine is the main building block of Node.js. The Node.js runtime environment includes several Node APIs to power the Node.js environment in addition to the V8 engine. We can enhance the functionality of our node code by installing extra npm packages.

One thing to keep in mind is that V8 is essentially a standalone C++ library that is utilized to run JavaScript code by Node or Chromium. V8 exposes an API that other applications can utilize, so you can embed V8 in your C++ program and run a JavaScript program from it. Node and Chrome work in this manner.

Memory limit of V8 in Node.js

Currently, V8 has a RAM limit of 512MB on 32-bit computers and 1GB on 64-bit platforms by default. This limit can be increased by setting –max-old-space-size to a maximum of ~1gb for 32-bit and ~1.7gb for 64-bit systems. If you’re running out of memory, it’s a good idea to break your single process into numerous workers.

Can Node.js work without V8?

V8 is required for the current Node.js engine to function. In the absence of V8, it wouldn’t have a JavaScript engine, and thus wouldn’t be able to run JavaScript code. The V8 interface between C++ and JavaScript is used by the native code bindings that come with Node.js, such as the fs (File System) module and the Net module.


Why is LIBUV needed in Node JS?

libuv is a C library to abstract non-blocking I/O operations. It provides the following features :

  • It allows the CPU and other resources to be used simultaneously while still performing I/O operations, thereby resulting in efficient use of resources and network.
  • It facilitates an event-driven approach wherein I/O and other activities are performed using callback-based notifications.
  • It provides mechanisms to handle file system, DNS, network, child processes, pipes, signal handling, polling and streaming
  • It also includes a thread pool for offloading work for some things that can't be done asynchronously at the operating system level.

How V8 compiles JavaScript code?

Compilation is the process of converting human-readable code to machine code. There are two ways to compile the code

  • Using an Interpreter: The interpreter scans the code line by line and converts it into byte code.
  • Using a Compiler: The Compiler scans the entire document and compiles it into highly optimized byte code.

The V8 engine uses both a compiler and an interpreter and follows **just-in-time (JIT) compilation to speed up the execution. JIT compiling works by compiling small portions of code that are just about to be executed. This prevents long compilation time and the code being compiles is only that which is highly likely to run.


How the Event Loop Works in Node.js?

The event loop allows Node.js to perform non-blocking asynchronous despite the fact that JavaScript is single-threaded. It is done by offloading operations to the system kernel whenever possible.

Node.js is a single-threaded application, but it can support concurrency via the concept of event and callbacks. Every API of Node.js is asynchronous and being single-threaded, they use async function calls to maintain concurrency. Node uses observer pattern. Node thread keeps an event loop and whenever a task gets completed, it fires the corresponding event which signals the event-listener function to execute.

Features of Event Loop:

  • Event loop is an endless loop, which waits for tasks, executes them and then sleeps until it receives more tasks.
  • The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task.
  • The event loop allows us to use callbacks and promises.
  • The event loop executes the tasks starting from the oldest first.

What are some commonly used timing features of Node.js?

The Timers module in Node.js contains functions that execute code after a set period of time. Timers do not need to be imported via require(), since all the methods are available globally to emulate the browser JavaScript API. There are four timing function in node js

  • setTimeout/clearTimeout: This is used to implement delays in code execution.
function myFunc(arg) {
  console.log(`arg was => ${arg}`);
}
setTimeout(myFunc, 1500, 'funky');

The above function myFunc() will execute as close to 1500 milliseconds (or 1.5 seconds) as possible due to the call of setTimeout().

The timeout interval that is set cannot be relied upon to execute after that exact number of milliseconds. This is because other executing code that blocks or holds onto the event loop will push the execution of the timeout back. The only guarantee is that the timeout will not execute sooner than the declared timeout interval.

  • setInterval/clearInterval: This is used to run a code block multiple times.
function intervalFunc() {
  console.log('Cant stop me now!');
}
setInterval(intervalFunc, 1500);

If there is a block of code that should execute multiple times, setInterval() can be used to execute that code. setInterval() takes a function argument that will run an infinite number of times with a given millisecond delay as the second argument. Just like setTimeout(), additional arguments can be added beyond the delay, and these will be passed on to the function call. Also like setTimeout(), the delay cannot be guaranteed because of operations that may hold on to the event loop, and therefore should be treated as an approximate delay.

  • setImmediate/clearImmediate: setImmediate() will execute code at the end of the current event loop cycle. This code will execute after any I/O operations in the current event loop and before any timers scheduled for the next event loop. This code execution could be thought of as happening "right after this", meaning any code following the setImmediate() function call will execute before the setImmediate() function argument.

The first argument to setImmediate() will be the function to execute. Any subsequent arguments will be passed to the function when it is executed. Here's an example:

console.log('before immediate');
setImmediate((arg) => {
  console.log(`executing immediate: ${arg}`);
}, 'so immediate');
console.log('after immediate');

The above function passed to setImmediate() will execute after all runnable code has executed, and the console output will be:

before immediate
after immediate
executing immediate: so immediate
  • process.nextTick:

When we pass a function to process.nextTick(), we instruct the engine to invoke this function at the end of the current operation, before the next event loop tick starts:

process.nextTick(() => {
  // do something
});

Both setImmediate and process.nextTick appear to be doing the same thing; however, the main diffrence between setImmediate and process.nextTick are:

  • process.nextTick() will run before any Immediates that are set as well as before any scheduled I/O.
  • process.nextTick() is non-clearable, meaning once code has been scheduled to execute with process.nextTick(), the execution cannot be stopped, just like with a normal function.

What is the difference between process.nextTick and setImmediate?

process.nextTick():

The process.nextTick() method adds the callback function to the start of the next event queue. It is to be noted that, at the start of the program process.nextTick() method is called for the first time before the event loop is processed.

setImmediate():

The setImmediate() method is used to execute a function right after the current event loop finishes. It is callback function is placed in the check phase of the next event queue.

Example:

setImmediate(() => {
  console.log("1st Immediate");
});
setImmediate(() => {
  console.log("2nd Immediate");
});
process.nextTick(() => {
  console.log("1st Process");
});
process.nextTick(() => {
  console.log("2nd Process");
});
// First event queue ends here
console.log("Program Started");
// Output
Program Started
1st Process
2nd Process
1st Immediate
2nd Immediate

Both setImmediate and process.nextTick appear to be doing the same thing; however, the main diffrence between setImmediate and process.nextTick are:

  • process.nextTick() will run before any Immediates that are set as well as before any scheduled I/O.
  • process.nextTick() is non-clearable, meaning once code has been scheduled to execute with process.nextTick(), the execution cannot be stopped, just like with a normal function.

What is callback function in Node.js?

A callback is a function which is called when a task is completed, thus helps in preventing any kind of blocking and a callback function allows other code to run in the meantime.

Callback is called when task get completed and is asynchronous equivalent for a function. Using Callback concept, Node.js can process a large number of requests without waiting for any function to return the result which makes Node.js highly scalable.

function message(name, callback) {
  console.log("Hi" + " " + name);
  callback();
}
// Callback function
function callMe() {
  console.log("I am callback function");
}
// Passing function as an argument
message("Node.JS", callMe);

Hi Node.JS
I am callback function

What is callback hell in Node.js?

The callback hell contains complex nested callbacks. Here, every callback takes an argument that is a result of the previous callbacks. In this way, the code structure looks like a pyramid, making it difficult to read and maintain. Also, if there is an error in one function, then all other functions get affected.

An asynchronous function is one where some external activity must complete before a result can be processed; it is "asynchronous" in the sense that there is an unpredictable amount of time before a result becomes available. Such functions require a callback function to handle errors and process the result.

firstFunction(function (a) {
  secondFunction(a, function (b) {
    thirdFunction(b, function (c) {
      // And so on…
    });
  });
});

How to avoid callback hell in Node.js?

  1. Managing callbacks using Async.js:

Async is a really powerful npm module for managing asynchronous nature of JavaScript. Along with Node.js, it also works for JavaScript written for browsers.

Async provides lots of powerful utilities to work with asynchronous processes under different scenarios.

npm install --save async
  1. Managing callbacks hell using promises:

Promises are alternative to callbacks while dealing with asynchronous code. Promises return the value of the result or an error exception. The core of the promises is the .then() function, which waits for the promise object to be returned.

The .then() function takes two optional functions as arguments and depending on the state of the promise only one will ever be called. The first function is called when the promise if fulfilled (A successful result). The second function is called when the promise is rejected.

Example:

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Successful!");
  }, 300);
});
  1. Using Async Await:

Async await makes asynchronous code look like it's synchronous. This has only been possible because of the reintroduction of promises into node.js. Async-Await only works with functions that return a promise.

Example:

const getrandomnumber = function(){
    return new Promise((resolve, reject)=>{
        setTimeout(() => {
            resolve(Math.floor(Math.random() * 20));
        }, 1000);
    });
}
const addRandomNumber = async function(){
    const sum = await getrandomnumber() + await getrandomnumber();
    console.log(sum);
}
addRandomNumber();

How Node.js read the content of a file?

The "normal" way in Node.js is probably to read in the content of a file in a non-blocking, asynchronous way. That is, to tell Node to read in the file, and then to get a callback when the file-reading has been finished. That would allow us to handle several requests in parallel.

<!-- index.html -->
<html>
<body>
  <h1>File Header</h1>
  <p>File Paragraph.</p>
</body>
</html>
const http = require('http');
const fs = require('fs');

http.createServer(function (req, res) {
  fs.readFile('index.html', function(err, data) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    res.end();
  });
}).listen(3000);

How many types of streams present in node js?

Streams are objects that let you read data from a source or write data to a destination in continuous fashion. There are four types of streams

  • Readable − Stream which is used for read operation.
  • Writable − Stream which is used for write operation.
  • Duplex − Stream which can be used for both read and write operation.
  • Transform − A type of duplex stream where the output is computed based on input. Each type of Stream is an EventEmitter instance and throws several events at different instance of times.

Methods:

  • data − This event is fired when there is data is available to read.
  • end − This event is fired when there is no more data to read.
  • error − This event is fired when there is any error receiving or writing data.
  • finish − This event is fired when all the data has been flushed to underlying system.
  1. Reading from a Stream:
const fs = require("fs");
let data = "";
// Create a readable stream
const readerStream = fs.createReadStream("file.txt");
// Set the encoding to be utf8.
readerStream.setEncoding("UTF8");
// Handle stream events --> data, end, and error
readerStream.on("data", function (chunk) {
  data += chunk;
});
readerStream.on("end", function () {
  console.log(data);
});
readerStream.on("error", function (err) {
  console.log(err.stack);
});
  1. Writing to a Stream:
const fs = require("fs");
const data = "File writing to a stream example";
// Create a writable stream
const writerStream = fs.createWriteStream("file.txt");
// Write the data to stream with encoding to be utf8
writerStream.write(data, "UTF8");
// Mark the end of file
writerStream.end();
// Handle stream events --> finish, and error
writerStream.on("finish", function () {
  console.log("Write completed.");
});
writerStream.on("error", function (err) {
  console.log(err.stack);
});
  1. Piping the Streams:

Piping is a mechanism where we provide the output of one stream as the input to another stream. It is normally used to get data from one stream and to pass the output of that stream to another stream. There is no limit on piping operations.

const fs = require("fs");
// Create a readable stream
const readerStream = fs.createReadStream('input.txt');
// Create a writable stream
const writerStream = fs.createWriteStream('output.txt');
// Pipe the read and write operations
// read input.txt and write data to output.txt
readerStream.pipe(writerStream);
  1. Chaining the Streams:

Chaining is a mechanism to connect the output of one stream to another stream and create a chain of multiple stream operations. It is normally used with piping operations.

const fs = require("fs");
const zlib = require('zlib');
// Compress the file input.txt to input.txt.gz
fs.createReadStream('input.txt')
   .pipe(zlib.createGzip())
   .pipe(fs.createWriteStream('input.txt.gz'));
  
console.log("File Compressed.");

How to handle large data in Node.js?

The Node.js stream feature makes it possible to process large data continuously in smaller chunks without keeping it all in memory. One benefit of using streams is that it saves time, since you don't have to wait for all the data to load before you start processing. This also makes the process less memory-intensive.

Some of the use cases of Node.js streams include:

Reading a file that's larger than the free memory space, because it's broken into smaller chunks and processed by streams. For example, a browser processes videos from streaming platforms like Netflix in small chunks, making it possible to watch videos immediately without having to download them all at once.

Reading large log files and writing selected parts directly to another file without downloading the source file. For example, you can go through traffic records spanning multiple years to extract the busiest day in a given year and save that data to a new file.


Is Node.js entirely based on a single thread?

Yes, it is true that Node.js processes all requests on a single thread. But it is just a part of the theory behind Node.js design. In fact, more than the single thread mechanism, it makes use of events and callbacks to handle a large no. of requests asynchronously.

Moreover, Node.js has an optimized design which utilizes both JavaScript and C++ to guarantee maximum performance. JavaScript executes at the server-side by Google Chrome v8 engine. And the C++ lib UV library takes care of the non-sequential I/O via background workers.

To explain it practically, let's assume there are 100s of requests lined up in Node.js queue. As per design, the main thread of Node.js event loop will receive all of them and forwards to background workers for execution. Once the workers finish processing requests, the registered callbacks get notified on event loop thread to pass the result back to the user.


How does Node.js handle child threads?

Node.js is a single threaded language which in background uses multiple threads to execute asynchronous code. Node.js is non-blocking which means that all functions ( callbacks ) are delegated to the event loop and they are ( or can be ) executed by different threads. That is handled by Node.js run-time.

  • Nodejs Primary application runs in an event loop, which is in a single thread.
  • Background I/O is running in a thread pool that is only accessible to C/C++ or other compiled/native modules and mostly transparent to the JS.
  • Node v11/12 now has experimental worker_threads, which is another option.
  • Node.js does support forking multiple processes ( which are executed on different cores ).
  • It is important to know that state is not shared between master and forked process.
  • We can pass messages to forked process ( which is different script ) and to master process from forked process with function send.

How does Node.js support multi-processor platforms?

Since Node.js is by default a single thread application, it will run on a single processor core and will not take full advantage of multiple core resources. However, Node.js provides support for deployment on multiple-core systems, to take greater advantage of the hardware. The Cluster module is one of the core Node.js modules and it allows running multiple Node.js worker processes that will share the same port.

The cluster module helps to spawn new processes on the operating system. Each process works independently, so you cannot use shared state between child processes. Each process communicates with the main process by IPC and pass server handles back and forth.

Cluster supports two types of load distribution:

  • The main process listens on a port, accepts new connection and assigns it to a child process in a round robin fashion.
  • The main process assigns the port to a child process and child process itself listen the port.

How does the cluster module work in Node.js?

The cluster module provides a way of creating child processes that runs simultaneously and share the same server port.

Node.js runs single threaded programming, which is very memory efficient, but to take advantage of computers multi-core systems, the Cluster module allows you to easily create child processes that each runs on their own single thread, to handle the load.

const cluster = require("cluster");
if (cluster.isMaster) {
  console.log(`Master process is running...`);
  cluster.fork();
  cluster.fork();
} else {
  console.log(`Worker process started running`);
}
output:
Master process is running...
Worker process started running
Worker process started running

How to make use of all CPUs in Node.js?

A single instance of Node.js runs in a single thread. To take advantage of multi-core systems, the user will sometimes want to launch a cluster of Node.js processes to handle the load. The cluster module allows easy creation of child processes that all share server ports.

The cluster module supports two methods of distributing incoming connections.

  • The first one (and the default one on all platforms except Windows), is the round-robin approach, where the master process listens on a port, accepts new connections and distributes them across the workers in a round-robin fashion, with some built-in smarts to avoid overloading a worker process.

  • The second approach is where the master process creates the listen socket and sends it to interested workers. The workers then accept incoming connections directly.

Example:

const cluster = require("cluster");
const express = require("express");
const os = require("os");
if (cluster.isMaster) {
  console.log(`Master PID ${process.pid} is running`);
  // Get the number of available cpu cores
  const nCPUs = os.cpus().length;
  // Fork worker processes for each available CPU core
  for (let i = 0; i < nCPUs; i++) {
    cluster.fork();
  }
  cluster.on("exit", (worker, code, signal) => {
    console.log(`Worker PID ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an Express server
  const app = express();
  app.get("/", (req, res) => {
    res.send("Node is Running...");
  });

  app.listen(3000, () => {
    console.log(`App listening at http://localhost:3000/`);
  });

  console.log(`Worker PID ${process.pid} started`);
}

Running Node.js will now share port 3000 between the workers:

Output:

Master PID 13972 is running
Worker PID 5680 started
App listening at http://localhost:3000/
Worker PID 14796 started
...

What is difference between spawn and fork methods in Node.js?

  1. spawn():

In Node.js, spawn() launches a new process with the available set of commands. This doesn't generate a new V8 instance only a single copy of the node module is active on the processor.

It is used when we want the child process to return a large amount of data back to the parent process.

When spawn is called, it creates a streaming interface between the parent and child process. Streaming Interface — one-time buffering of data in a binary format.

Example:

const { spawn } = require("child_process");
const child = spawn("dir", ["D:\\empty"], { shell: true });
child.stdout.on("data", (data) => {
  console.log(`stdout ${data}`);
});
  1. fork():

The fork() is a particular case of spawn() which generates a new V8 engines instance. Through this method, multiple workers run on a single node code base for multiple tasks.

It is used to separate computation-intensive tasks from the main event loop.

When fork is called, it creates a communication channel between the parent and child process Communication Channel — messaging

Example:

/**
 * The fork() method
 */
const { fork } = require("child_process");
const forked = fork("child.js");
forked.on("message", (msg) => {
  console.log("Message from child", msg);
});
forked.send({ message: "fork() method" });
/**
 * child.js
 */
process.on("message", (msg) => {
  console.log("Message from parent:", msg);
});
let counter = 0;
setInterval(() => {
  process.send({ counter: counter++ });
}, 1000);

Output:

Message from parent: { message: 'fork() method' }
Message from child { counter: 0 }
Message from child { counter: 1 }
Message from child { counter: 2 }
...
...
Message from child { counter: n }

What are the preferred method of resolving unhandled exceptions in Node.js?

Unhandled exceptions in Node.js can be caught at the Process level by attaching a handler for uncaughtException event.

process.on('uncaughtException', function(err) {
    console.log('Caught exception: ' + err);
});

Process is a global object that provides information about the current Node.js process. Process is a listener function that is always listening to events.

Few events are :

  1. Exit
  2. disconnect
  3. unhandledException
  4. rejectionHandled

How to solve Process out of Memory Exception in Node.js?

Process out of Memory Exception is an exception that occurs when your node.js program gets out of memory. This happens when the default memory allocated to our program gets exceeded by our program while execution.

This exception can be solved by increasing the default memory allocated to our program to the required memory by using the following command.

Syntax:

node --max-old-space-size=<NEW_SIZE_IN_MB> index.js
/**
 * OutOfMemory Exception
 */
let items = [];

for (let i = 0; i < 999999999; i++) {
  items.push(i);
}

console.log(items);
<--- Last few GCs --->

[11652:000001DA4373BE50]      581 ms: Scavenge 765.9 (799.0) -> 765.9 (799.0) MB, 29.6 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure    
[11652:000001DA4373BE50]      844 ms: Scavenge 1148.4 (1181.6) -> 1148.4 (1181.6) MB, 44.7 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure

[11652:000001DA4373BE50]     1239 ms: Scavenge 1722.2 (1755.4) -> 1722.2 (1755.4) MB, 67.5 / 0.0 ms  (average mu = 1.000, current mu = 1.000) allocation failure


<--- JS stacktrace --->

FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
 1: 00007FF784AA052F napi_wrap+109311
 2: 00007FF784A45256 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NumberOfElementsOffset+33302
 3: 00007FF784A46026 node::OnFatalError+294
 4: 00007FF78531163E v8::Isolate::ReportExternalAllocationLimitReached+94
 5: 00007FF7852F64BD v8::SharedArrayBuffer::Externalize+781
 6: 00007FF7851A094C v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1516
 7: 00007FF7851C547F v8::internal::Factory::NewUninitializedFixedArray+111
 8: 00007FF78508B3C0 v8::Object::GetIsolate+8128
 9: 00007FF784F151F7 v8::internal::interpreter::JumpTableTargetOffsets::iterator::operator=+169671
10: 00007FF785399FED v8::internal::SetupIsolateDelegate::SetupHeap+463949
11: 000003EC8D443246

The default memory allocated to a node.js program is 512MB on 32-bit systems and 1024MB on 64-bit systems. In the below example, we have increased the memory space requirements to 2048MB or 2GB. Use the following command to run the JS file(index.js).

Example:

node --max-old-space-size=2048 index.js

What is event emmiter class in node.js?

The event loop allows Node.js to perform non-blocking I/O operations despite the fact that JavaScript is single-threaded. It is done by offloading operations to the system kernel whenever possible.

Node.js is a single-threaded application, but it can support concurrency via the concept of event and callbacks. Every API of Node.js is asynchronous and being single-threaded, they use async function calls to maintain concurrency. Node uses observer pattern. Node thread keeps an event loop and whenever a task gets completed, it fires the corresponding event which signals the event-listener function to execute.

Features of Event Loop:

  • Event loop is an endless loop, which waits for tasks, executes them and then sleeps until it receives more tasks.
  • The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task.
  • The event loop allows us to use callbacks and promises.
  • The event loop executes the tasks starting from the oldest first.
const events = require('events');
const eventEmitter = new events.EventEmitter();
// Create an event handler as follows
const connectHandler = function connected() {
   console.log('connection succesful.');
   eventEmitter.emit('data_received');
}
// Bind the connection event with the handler
eventEmitter.on('connection', connectHandler);
// Bind the data_received event with the anonymous function
eventEmitter.on('data_received', function() {
   console.log('data received succesfully.');
});
// Fire the connection event 
eventEmitter.emit('connection');
console.log("Program Ended.");
// Output
Connection succesful.
Data received succesfully.
Program Ended.

How child process works node.js?

Processes

The processes in a computer are all the programs that are running and interacting with the processor. When starting a process, the operating system allocates memory and resources for its execution. At the end of a process, the system releases these resources, and the management method depends on the way each particular operating system works.

Some characteristics to highlight of the processes:

Every process initially starts with a single main thread.

  • A process is composed of one or more threads.
  • A process can instantiate other processes called subprocesses.

Subprocess concept

A subprocess is an option to encapsulate logically related steps within a parent process. The subprocess supports the parent process to perform different programmatic tasks in the background.

Some noteworthy features of the subprocess:

  • They are instantiated by a parent process.
  • The subprocess as such is a process, so they are also made up of 1 or more threads and can create more sub-processes. Subprocess en Nodejs

Subprocess in Nodejs

Many of today’s programming languages contain at their core multiple mechanisms for spawning and interacting with subprocesses. Nodejs in particular contains a module called child_process that helps us with this task.

Some examples of subprocesses to instantiate:

  • Open a browser.
  • Ping an IP address.
  • Open the notepad.
  • Execute commands by console.

To run child process node.js, NodeJs provide child-process built in module.The child_process module contains the following main methods that will help us create, manipulate, and run processes: exec, spawn, and fork.

  1. Exec:

The exec method spawns a new shell process and proceeds with executing commands in that shell.

In the following example, we instantiate a shell process and execute the ping command with the address of google.com.

const { exec } = require('child_process');
exec('ping google.com', (error, stdout, stderr) => {
    if (error) {
        console.error(`error: ${error.message}`);
        return;
    }
    if (stderr) {
        console.error(`stderr: ${stderr}`);
        return;
    }
    console.log(`stdout:\n${stdout}`);
});

This results in the following:

Pinging google.com [142.251.0.101] with 32 bytes of data:
Reply from 142.251.0.101: bytes=32 time=7ms TTL=107
Reply from 142.251.0.101: bytes=32 time=11ms TTL=107
Reply from 142.251.0.101: bytes=32 time=11ms TTL=107
Reply from 142.251.0.101: bytes=32 time=8ms TTL=107
Ping statistics for 142.251.0.101: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds: Minimum = 7ms, Maximum = 11ms, Average = 9ms
  1. spawn The spawn method creates a new process by executing a command with stream manipulation. This method is intended for working with intensive workloads.

In the following example we run the command find to search for files in the current directory and listen for events on stdout, stderr, error, and close. All worked with streams.

const { spawn } = require('child_process');
const subProcess = spawn("find", ["."]);
subProcess.stdout.on('data', (data) => {
  console.log(`stdout:\n${data}`);
});
subProcess.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});
subProcess.on('error', (error) => {
  console.error(`error: ${error.message}`);
});
subProcess.on('close', (code) => {
  console.log(`child process salida ${code}`);
});

This results in the following (my files at the time):

stdout:
.
./array_2D.js
child process salida 0

Unlike exec which works with callbacks, spawnworks with streams. This allows us to run processes much longer and in a much more asynchronous way.

  1. fork The fork method spawns a new process with communication between parent and child (process and thread). This method is intended to work with bifurcations and convergence.

In the following example, we will instantiate a child process that will send information to the parent process in 5 seconds (asynchronous simulation).

child process (child.js)

setTimeout(() => {
  process.send("Hello father, I send this information")
}, 5000);

parent process (father.js)

const { fork } = require('child_process');
const subProcess = fork("./child.js");
subProcess.on('message', (message) => {
  console.log(`I get this from the son : ${message}`);
});

This results in the following:

I get this from the son : Hello father, I send this information

Messages between a parent and child process created by forkthey are accessible through Node global object called “process”. Also, with forkwe can control when a child process starts an activity or also return data from a child process to a parent process and vice versa.