
Node JS Interview Questions
If you wish to make a career in Node JS, below are the top Node JS interview questions with answers which will make you interview-ready.
A comprehensive, community-driven list of essential Node js interview questions. Whether you’re a candidate or interviewer, these interview questions will help prepare you for your next Node.js interview ahead of time.
Basic understanding of Node JS
Node js can be used to build different types of applications, such as web applications, real-time chat applications, REST API servers, etc. Nonetheless, it is primarily used to create network programs such as web servers, similar to PHP, Java, or ASP.NET. Node js was created in 2009 by Ryan Dahl.
Node js is a run-time JavaScript environment developed on top of the Chrome V8 engine. Uses an event-driven, non-blocking I / O model. It’s lightweight and it’s so effective. Node js has an architecture module called npm.
In its elementary sense, Node js is a JS runtime built using the Chrome V8 JavaScript engine as a platform. Node js has gained popularity as it is lightweight and efficient, mainly due to its event-driven and non-blocking I / O model. Built with performance as its primary goal, Node js is responsible for translating the JavaScript code into the native machine code, which can then be used by your computer to execute the operation.
While it is based on the V8 engine used in Google Chrome and other chromium-based browsers (Vivaldi, Brave and Opera), it does not run in the browser itself. Throughout creation, various features such as file system API, HTTP server, and OS utility methods have been added to the engine so that Node js can be run as a program on a device.
Event-Driven Programming is a concept that is commonly used when referring to the flow of events by tapping, loading, and so on. EDP is very significant when it comes to the most common programming languages of today, such as java and c #.
The event-driven method is used in Node JS. What is surprising is that the Node JS application runs through a single thread but with a callback system, it is very possible to achieve concurrence.
How does the Node application work?
Callback is an event that is invoked immediately after the completion of a certain task. Most Node JS APIs are single threaded; therefore, asynchronous function calls are required to allow concurrency maintenance.
The Observer Pattern helps the Node JS thread to manage the event loop. As a consequence, the corresponding task is initialized immediately and sends a signal to the event-listener to start its execution.
An overview of the Event Driven Programming.

In this concept, the event emitter emits several events and the main loop immediately listens to them, which causes a callback function to be triggered after the loop event is detected. The function of the event emitter is therefore to simplify the interaction of the event loop. The callback functions like an case, but it is only called in the case that the asynchronous returns its output.
Node JS relies heavily on the use of events , making it a relatively fast application compared to other similar technologies. Once the server node begins, it initiates the variables, announces and waits for the event to operate. Several built-in modules within Node JS, together with the Event Emitter, connect the event types to a simplified and personalized listener.
It is also clear that Node JS event modules are responsible for the creation of events, event handlers and emitters. An event loop consists of an entry region where an event is triggered by invoking the event handler to produce more than one event that will execute the event one after the other, thereby generating the event drive programming.
Callback Hell is a phenomenon that affects JavaScript developers when they seek to run several asynchronous operations one after the other. Some people call it the doom pyramid. Let’s take a look at an example of what we call hell back.
doSomething(param1, param2, function(err, paramx){
doMore(paramx, function(err, result){
insertRow(result, function(err){
yetAnotherOperation(someparameter, function(s){
somethingElse(function(x){
});
});
});
});
});
This is looking bad just from the skeleton itself. In real code you will obviously have other statements like if
, for
or some other operations along with these nested functions. Add those to the above code and it would get really messy and unmanageable.
Suggestion:
Don’t strain your tasks. Most of the time, it may be likely that the real problem you ‘re facing isn’t a callback hell, it’s a badly written function. For these instances, the solutions we’ll see below will structure your code, but they’re not going to solve the real problem. So, as a rule of thumb, make your role do less, that is, write small functions that perform a single task.
Techniques for avoiding callback hell
There are a number of techniques for dealing with callback hell. In particular, we’ll take a look at the three below.
- Using Async.js
- Using Promises
- Using Async-Await
Managing callbacks with Async.js
Async is a very powerful npm module for managing the asynchronous nature of JavaScript. It also works for JavaScript written for browsers, along with Node JS.
Async provides a lot of powerful utilities to work with asynchronous processes under different scenarios.
async.waterfall()
Async Waterfall is useful when you want to perform certain tasks one after the other and at the same time move the outcome from the previous task to the next.
async.waterfall()
takes in an array of functions 'tasks'
and a final 'callback'
function which is called after all the functions in tasks
have completed or a callback
is called with an error.
var async = require('async');
async.waterfall([
function(callback) {
//doSomething
callback(null, paramx); //paramx will be availaible as the first parameter to the next function
/**
The 1st parameter passed in callback.
@null or @undefined or @false control moves to the next function
in the array
if @true or @string the control is immedeatly moved
to the final callback fucntion
rest of the functions in the array
would not be executed
*/
},
function(arg1, callback) {
//doSomething else
// arg1 now equals paramx
callback(null, result);
},
function(arg1, callback) {
//do More
// arg1 now equals 'result'
callback(null, 'done');
},
function(arg1, callback) {
//even more
// arg1 now equals 'done'
callback(null, 'done');
}
], function (err, result) {
//final callback function
//finally do something when all function are done.
// result now equals 'done'
});
So using async.waterfall() you would be writing you code vertically instead of indenting it horizontally and entering the pyramid of doom. Plus your code would be much more structured and easy to read.
async.series()
Async provides another method for managing series execution, async.series()
. Async series works in the same way as Async waterfall, by executing functions in the array one after the other, with the difference that it will not pass data from one function to another, instead, when all functions have completed their execution, the function result will be available as an array in the final callback.
Similar to async.waterfall()
in async.series()
as well, when all of the functions are called with an error callback, no further functions are performed in the list and the final callback is immediately called with an error value. Have a look for a direct picture below.
var async = require('async');
async.series([
function(callback){
// do some stuff ...
callback(null, 'one');
/**
The 1st parameter passed in callback.
@null or @undefined or @false control moves to the next function
in the array
if @true or @string the control is immedeatly moved
to the final callback fucntion with the value of err same as
passed over here and
rest of the functions in the array
would not be executed
*/
},
function(callback){
// do some more stuff ...
callback(null, 'two');
}
],
// optional callback
function(err, results){
// results is now equal to ['one', 'two']
});
There are more interesting functions available with the Async module to make sure you check them out and use them in your Node JS projects.
Visit Async.js Website
Managing callbacks with Promises
Promises are an alternative to callbacks when dealing with asynchronous code. Promises return the value of the result or an exception to the error. The center of the promise 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 promise status, only one will be called. The first role is named when the promise is fulfilled (a positive outcome). The second function is called when the promise has been rejected.
Let’s see the structure of a typical vow.
var outputPromise = getInputPromise().then(function (input) {
//handle success
}, function (error) {
//handle error
});
Chaining promises
We may also render chain guarantees, this is an identical option to nesting callbacks. There are two ways to keep promises in chains. Promises can be chained within or outside the handler (.then()
function). Chaining promises outside the handle is a lot clean and easy to read, but we may have to chain promises within the handler if we want to use any parameter in our next handler that is accessible within the reach of the previous handler.
But too much chaining within the handler will again result in a horizontal code that we are trying to prevent. We may also make chain guarantees with a mixture of inner and outer chains. For a general rule, I would recommend that you stop chaining within the handler.
However, another positive thing about chaining promises is that we can, however, add a catch block at the end of the chain to capture any error that happens in any of the relevant functions.
return getUsername().then(function (username) {
return getUser(username);
})
.then(function (user) { //example of chaining outside the handler
return userPassword().then(function(password){
/**
example of chaining inside the handler,
since we need to use the @user param
from the previous handler scope
*/
if(user.password !== password){
//reject promise or throw error
return;
}
});
})
.catch(function(e){
//handle error
console.log(e);
});
Creating a function that returns a Promise
To create a function that works with promises we can use the in-built Promise
class.
const test = function(){
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('done');
}, 10);
});
}
//call it like this
test().then((resp)=>{
console.log(resp);
})
.catch((e)=>{
console.log(e);
});
A promise is considered successful if the value is returned with the resolve
method and unsuccessful if it is returned with the reject
method.
Managing callbacks with Async Await
Some of the best things to come out of Node JS recently is the Async-Wait function. Async Wait makes the asynchronous code look like it’s synchronous. It was only possible because of the re-introduction of promises into Node JS. Async-Await only works with a promise-returning feature.
For now, the only way to prevent a callback is to use async-wait in Node JS. Let’s use an example to understand this.
const getrandomnumber = function(){
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve(Math.floor(Math.random() * 20));
}, 1000);
});
}
const addRandomNumber = async function(){
try {
const sum = await getrandomnumber() + await getrandomnumber();
console.log(sum);
} catch (error) {
//handle error
console.log(error);
}
}
addRandomNumber();
As you see above, we have a function that returns a random number after 1 sec. This function returns a promise. Use the await keyword, we tell JavaScript to wait for the response before going on. But this await keyword only works within functions that are declared to be async. If we declare a function to be async, we ‘re asking JavaScript to pause the execution before the result arrives when it comes to the await keyword.
Now, in promises to handle the failure, we might directly chain the catch block. How would you do it in the above case? Okay, we can only use the try-catch block.
Node JS is basically a single thread operation. This does not expose the developer to child threads and thread management methods. Technically, Node JS creates child threads for certain functions, such as asynchronous I / O, but they run behind the scenes and do not execute any JavaScript code or block the main event loop.
If threading support is desired in a Node JS application, there are tools available to enable it, such as the ChildProcess module.
ES6 Interview Questions and Answers
Node JS is a single-threaded event-driven platform capable of non-blocking, asynchronous programming. These functions of Node JS make memory efficient. The event loop allows Node JS to perform non-blocking I / O operations despite the fact that JavaScript is single threaded. It is achieved by assigning tasks to the operating system whenever and wherever possible.
Most operating systems are multi-threaded and hence can handle multiple operations executing in the background. When one of these operations is completed, the kernel tells Node JS and the respective callback assigned to that operation is added to the event queue which will eventually be executed. This will be explained further in detail later in this topic.
Event Loop features:
- Event loop is an infinite loop that waits for tasks, executes them, and then sleeps before more tasks are provided.
- 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 makes it possible for us to use callbacks and commitments.
- The event loop will perform tasks starting from the oldest one.
console.log("This is the first statement");
setTimeout(function(){
console.log("This is the second statement");
}, 1000);
console.log("This is the third statement");
//output
This is the first statement
This is the third statement
This is the second statement
Explanation
In the example above, the first console log statement is moved to the call list, and “This is the first statement” is logged in to the console, and the function is popped out of the list. First, the setTimeout is moved to the queue and the task is sent to the operating system and the timer is set to the task. This function is then popped out of the stack. Next, the third console log statement is moved to the call list, and “This is the third message” is logged in to the console, and the job is popped out of the list.
When the timer set by the setTimeout function (in this case 1000 ms) is run out, the callback is sent to the event queue. The event loop on finding the call stack empty takes the task to the top of the event queue and sends it to the call stack. The callback function for the setTimeout function will run the instruction and “This is the second message” will be logged in to the console and the task will pop up from the stack.
Working of the Event loop:
As Node JS begins, it initializes the event loop, processes the input script that can render async API calls, schedule timers, and then begins processing the event loop. In the previous case , the initial input script consisted of console.log()
statements and the setTimeout()
function, which sets the timer.
When using Node JS, a special library module called libuv is used to perform async operations. This library is also used, along with the back logic of Node, to handle a special thread pool called the libuv thread pool. This thread pool consists of four threads used to delegate operations that are too heavy for the event loop. I / O operations, Opening and closing connections, setTimeouts are examples of these operations.
When a thread pool completes a task, a callback function is called that handles an error (if any) or some other operation. This callback function is sent to the queue of the event. When the call stack is empty, the event passes through the event queue and sends the call back to the call stack.

Phases of the Event loop
- Timers: Callbacks scheduled by setTimeout() or setInterval() are executed in this phase.
- Pending Callbacks: I/O callbacks deferred to the next loop iteration are executed here.
- Idle, Prepare: Used internally only.
- Poll: Retrieves new I/O events.
- Check: It invokes setIntermediate() callbacks.
- Close Callbacks: It handles some close callbacks. Eg: socket.on(‘close’, …)
Node js is a simplified model created because there have been several problems recorded in server side programming. Node.js uses different modules that are responsible for different core features. It runs on a number of operating systems, such as MacOS, Linux , and Windows. To optimize the use of both a single CPU and memory, we use non-blocking and asynchronous operations. They will use only one thread to satisfy all requests.
Asynchronous:
The word determines that it is not synchronous. The asynchronous architecture states that the sent message does not give an immediate reply just like we send the mail, but will not receive an immediate reply. It has no reliance or order. This increases the quality and performance of the program. The server stores the details and will be alerted when the action is taken.
Non-Blocking:
Immediately unblocking reactions with whatever data is available. In addition, it does not block any execution and continues to run as per requests. If a response can not be retrieved, the API will return immediately with an error. Non-blocking is often used for I / O ( input / output). Node.js is based on a non-blocking I / O pattern. There are few means of interacting that have been achieved by a non-blocking I / O. The callback function is to be called when the process is over. The nonblocking call uses the support of a javascript that provides a callback function.
Asynchronous VS Non-Blocking
You can point out the differences with these definitions of asynchronous and nonblocking. But few major differences are:
- Asynchronous does not respond immediately, while Nonblocking responds immediately if the data is available and if not, it simply returns an error.
- Asynchronous increases performance by completing the job quickly as the response can come later, whereas other tasks can be completed. Nonblocking does not obstruct any execution and, if the data is available, retrieves the information quickly.
- Asynchronous is the opposite of synchronous whereas non-blocking I / O is the opposite of blocking. They are both fairly similar, but they are also different because asynchronous is used with a wider range of operations, while non-blocking is mostly used with I / O.
Tracing provides a mechanism for collecting tracking information generated by V8, Node Core and userspace code in a log file. Tracing can be allowed by passing the --trace-events-enabled
flag when beginning the Node.js program.
node --trace-events-enabled --trace-event-categories v8, node server.js
The set of categories for which traces are recorded can be specified using the --trace-event-categories
flag followed by a list of comma-separated category names. The node and v8 categories are enabled by default.
Running Node.js with tracing enabled will produce log files that can be opened in the chrome://tracing
tab of Chrome.
setTimeout
It is simply like calling the function after delay has finished. Once a function is called, it is not executed immediately, but is queued in such a way that it is executed after all the running and currently queued eventhandlers finish first. SetTimeout(,0) effectively implies that all existing functions in the existing queue are executed. There can be no assurances as to how long it will take.
setImmediate
It is similar in this regard, except that it does not use the function queue. Checks the queue of I / O event handlers. If all I / O events in the current snapshot are processed, the callback will be executed. It queues them immediately after the last I / O handler a bit like process.nextTick. It’s quicker, then.
Even (setTimeout,0) will be slow because the timer must be tested at least once before running. It can be twice as slow at times. Here’s the comparison.
setTimeout(function() {
console.log('setTimeout')
}, 0)
setImmediate(function() {
console.log('setImmediate')
})
As you try to grasp the Node.js event loop, the process.nextTick()
is an important part of it. Every time the event loop goes on a full trip, we call it a tick. When a function is transferred 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
})
The event loop is busy processing the current function code. Once this operation finishes, the JS engine must run all the functions passed to nextTick during this process.
That is the way we can tell the JS engine to process the function asynchronously (after the current function), but as soon as possible, not queue it.
Calling setTimeout(() => {}, 0)
would execute the function at the end of the next tick, much later than using nextTick()
to prioritize the request and execute it just before the start of the next tick. Using nextTick()
to make sure that the code is already executed in the next event loop iteration.
21 React js Interview Questions and Answers
There are two solutions to addressing unhandled exceptions in Node.js that are discussed below:
1. Using try-catch block:
We know that Node.js is a platform built on JavaScript runtime to easily create fast and scalable network applications. Being part of JavaScript, we know that the most important way to deal with the exception is to try and catch a block.
try {
// The synchronous code that
// we want to catch thrown
// errors on
var err = new Error('Hello')
throw err
} catch (err) {
// Handle the error safely
console.log(err)
}
2. Using Process:
Good practice states that you will use the Process to handle the exception. A process is a global object that provides information on the current Node.js process. The process is a feature of the listener who often listens to events.
Some process events are:
- Disconnect
- Exit
- Message
- Multiple Resolves
- Unhandled Exception
- Rejection Handled
- Uncaught Exception
- Warning
The most effective and efficient solution is the use of the Process. If any uncaught or uncontrolled exception occurs in your code flow, the exception will be caught in the code shown below:
process.on('uncaughtException', function(err) {
// Handle the error safely
console.log(err)
})
The above code should be able to handle any kind of unhandled exception that exists in Node.js.
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.
Node Js is supporting clustering to take full advantages of your cpu. If you are not not running it with cluster, then probably you are wasting your hardware capabilities.
Clustering in Node.js allows you to create separate processes which can share same server port. For example, if we run one HTTP server on Port 3000, it is one Server running on Single thread on single core of processor. Code shown below allow you to cluster your application. This code is official code represented by Node.js.
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id) {
console.log("I am running with ID : " + cluster.workers[id].process.pid);
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
//Do further processing.
}
There are many of the most common, most starred, or most downloaded modules in Node.js. There are plenty of them:
- express
- async
- browserify
- socket.io
- bower
- gulp
- grunt
Node.js uses the Events Module to create and manage custom events. The EventEmitter class can be used to build and manage custom event modules.
The syntax for importing the event module is given below:
Syntax:
const EventEmitter = require('events');
All EventEmitters emit a newListener
event when new listeners are added and removeListener
when current listeners are removed. It also provides one more option
boolean captureRejections
Default Value: false
It automatically captures rejections.
Listening events:
before any event is emitted, the functions(callbacks) must be registered to listen to the events.
Syntax:
eventEmitter.addListener(event, listener)
eventEmitter.on(event, listener)
EventEmitter.on(event, listener)
and eventEmitter.addListener(event, listener)
are quite similar. At the end of the listener's sequence, it adds the listener to the specified event. Several calls to the same event and the listener can connect the listener multiple times and trigger multiple times. Both functions return the emitter, so that calls can be chained.
Emitting Events:
Each event is named event in nodejs. The event can be triggered by the emit(event, [arg1], [arg2], [...]) function. We may transfer an arbitrary set of arguments to the function of the listener.
Syntax:
eventEmitter.emit(event, [arg1], [arg2], [...])
Example
// Importing events
const EventEmitter = require('events');
// Initializing event emitter instances
var eventEmitter = new EventEmitter();
// Registering to myEvent
eventEmitter.on('myEvent', (msg) => {
console.log(msg);
});
// Triggering myEvent
eventEmitter.emit('myEvent', "First event");
Removing Listener:
The eventEmitter.removeListener()
takes two argument event and listener, and eliminates the listener from the listener array that is subscribed to that event. Although eventEmitter.removeAllListeners()
removes all listeners from the array that are subscribed to the event.
Syntax:
eventEmitter.removeListener(event, listener)
eventEmitter.removeAllListeners([event])
Special Events:
All EventEmitter instances emit the event 'newListener'
when new listeners are added and existing listeners 'removeListener'
deleted.
-
Event: 'newListener'
EventEmitter must emit its own 'new listener' event before the listener is added to its internal array of listeners. Listeners registered for the 'newListener' event will be transferred to the name of the event and a reference will be added to the listener. The 'newListener' event is triggered before the listener is added to the array.
eventEmitter.once( 'newListener', listener) eventEmitter.on( 'newListener', listener)
-
Event: 'removeListener'
The 'removeListener' event is emitted after a listener is removed
eventEmitter.once( 'removeListener', listener) eventEmitter.on( 'removeListener', listener)
-
Event: 'error'
If an error occurs inside the EventEmitter instance, the typical behavior is to emit a 'error' event. If the EventEmitter does not have at least one listener registered for the 'error' event, and the 'error' event is released, the error is thrown, the stack trace is written, and the Node.js process exits.
eventEmitter.on('error', listener)
Example:
// Importing events
const EventEmitter = require('events');
// Initializing event emitter instances
var eventEmitter = new EventEmitter();
// Register to error
eventEmitter.on('error', (err) => {
console.error('Attention! There was an error');
});
// Register to newListener
eventEmitter.on( 'newListener', (event, listener) => {
console.log(`The listener is added to ${event}`);
});
// Register to removeListener
eventEmitter.on( 'removeListener', (event, listener) => {
console.log(`The listener is removed from ${event}`);
});
// Declaring listener Indiahires1 to myEvent1
var Indiahires1 = (msg) => {
console.log("Message from Indiahires1: " + msg);
};
// Declaring listener Indiahires2 to myEvent2
var Indiahires2 = (msg) => {
console.log("Message from Indiahires2: " + msg);
};
// Listening to myEvent with Indiahires1 and Indiahires2
eventEmitter.on('myEvent', Indiahires1);
eventEmitter.on('myEvent', Indiahires2);
// Removing listener
eventEmitter.off('myEvent', Indiahires1);
// Triggering myEvent
eventEmitter.emit('myEvent', 'Event occurred');
// Triggering error
eventEmitter.emit('error', new Error('Attention!'));
Reference: https://nodejs.org/api/events.html#events_class_eventemitter
A stream is an abstract interface for streaming data in Node.js. The stream module provides an API for the implementation of the stream interface. There are a lot of stream objects supported by Node.js. For example, a request to an HTTP server and process.stdout
are both stream instances. Streams may be readable, writeable, or both. All streams are EventEmitter
instances.
To access the stream module:
const stream = require('stream');
The stream
module is useful to create new types of stream instances. Typically, it is not appropriate to use the stream
module to access streams.
Types of streams
There are four fundamental stream types within Node js:
-
Writable:
Streams to which data can be written (for example,
fs.createWriteStream()
). -
Readable:
Streams to which data can be written (for example,
fs.createReadStream()
). -
Duplex:
Streams that are both
Readable
andWritable
(for example,net.Socket
). -
Transform:
Duplex
streams that can modify or transform the data as it is written and read (for example,zlib.createDeflate()
In addition, this module contains the stream.pipeline()
, stream.finished()
and stream.Readable.from()
utility functions.
Every Stream type is an instance of EventEmitter and throws many events at different times. Many of the widely used cases , for example, are −
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.
Reading from a Stream
Create a js file named main.js with the following code −
var fs = require("fs");
var data = '';
// Create a readable stream
var readerStream = fs.createReadStream('input.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);
});
console.log("Program Ended");
Writing to a Stream
Create a js file named main.js with the following code −
var fs = require("fs");
var data = 'Simply Easy Learning';
// Create a writable stream
var writerStream = fs.createWriteStream('output.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);
});
console.log("Program Ended");
Now open output.txt that has been created in your current directory; it should contain the following.
Piping the Streams
Piping is a mechanism that provides the output of one stream as input to another stream. Typically, it is used to get data from one stream and transfer the output of that stream to another source. There is no limit to pipe operations. Now we're going to demonstrate a pipe example to read from one file and write it to another file.
Create a js file named main.js with the following code −
var fs = require("fs");
// Create a readable stream
var readerStream = fs.createReadStream('input.txt');
// Create a writable stream
var writerStream = fs.createWriteStream('output.txt');
// Pipe the read and write operations
// read input.txt and write data to output.txt
readerStream.pipe(writerStream);
console.log("Program Ended");
Chaining the Streams
Chaining is a mechanism to connecting the output of one stream to another stream and forming a chain of multiple stream operations. It is normally used for pipe operations. Now we're going to use pipe and chaining to first compress a file and then decompress the same one.
var fs = require("fs");
var 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.");
Node JS core modules, as well as most community-published modules, follow a pattern where the first argument for every callback handler is an optional error object. If there is no error, the argument is null or undefined.
Therefore, the typical callback handler could perform error handling as follows:
function callback(err, results) {
// usually we'll check for the error before handling results
if(err) {
// handle error somehow and return
}
// no error, perform standard callback handling
}
Node.js is an open-source JavaScript running-time environment built on the Chrome JavaScript Engine(V8). Node.js is used to create fast and scalable applications and is an event oriented, non-blocking I / O model.
REPL (RED, EVAL, PRINT, LOOP) is a programming environment close to Shell (Unix / Linux) and a command prompt. Node comes with the REPL system when it's built. The program communicates with the user via the output of the commands / expressions used. It is useful for writing and debugging codes. The function of REPL can be understood in its full form:
Read :
It reads the inputs from users and parses it into JavaScript data structure. It is then stored to memory.
Eval :
The parsed JavaScript data structure is evaluated for the results.
Print :
The result is printed after the evaluation.
Loop :
Loops the input command. To come out of NODE REPL, press ctrl+c twice
fs.createReadStream(
and fs.readFile(
both are asynchronous, right !!
Well, aside from the fact that fs.createReadStream()
explicitly returns a stream object, and fs.readFile()
requires a callback function in the second statement, there's another big difference.
Yes, they 're both asynchronous, but that doesn't change the fact that fs.readFile()
doesn't send you any data unless the entire file has been buffered into memory. It is much less memory-efficient and slower when it comes to relaying data back via server responses. With fs.createReadStream()
, you can directly pipe the stream object to the server response object, which ensures that your client will automatically start receiving data even if the file is 500 MB.
Not only that, but you 're also enhancing memory capacity by working with a single chunk file at a time rather than all at once. This means that your memory only needs to buffer the contents of the file a few kilobytes at a time rather than all at once.
Here are two snippets showing:
const fs = require('fs');
const http = require('http');
// using readFile()
http.createServer(function (req, res) {
// let's pretend this is a huge 500MB zip file
fs.readFile('some/file/path.zip', function (err, data) {
// entire file must be buffered in memory to data, which could be very slow
// entire chunk is sent at once, no streaming here
res.write(data);
res.end();
});
});
// using createReadStream()
http.createServer(function (req, res) {
// processes the large file in chunks
// sending them to client as soon as they're ready
fs.createReadStream('some/file/path.zip').pipe(res);
// this is more memory-efficient and responsive
});
Crypto is a module in Node.js that deals with an algorithm that performs data encryption and decryption. This is used for security purposes, such as user authentication, where the password is stored in an encrypted form in the Database.
The Crypto module provides a set of classes such as hash, HMAC, cipher, decipher, sign, and verify. This class instance is used to create Encryption and Decryption. Node.js is unable to construct a class object using a new keyword.
How to use?
To use the crypto module in Node.js then first require crypto.
var crypto = require('crypto');
To get all Cipher algorithms that support crypto in a Node js run following command.
require("crypto").getCiphers()
Encryption
The method of transforming readable text to an unreadable format called Encryption. Encryption is used in Node.js, then the following method is used.
const crypto = require('crypto');
const password ='crypto@123';
const cipher = crypto.createCipher('aes128', 'a password');
var encrypted = cipher.update(password, 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);
Cipher is a class in which crypto.createCipher) (is a method that creates an instance of that class. The instance of that class is used to convert plain text into an unreadable format.
In Example string ‘crypto@123’ is a plain password and using .update() and .final() method with ‘aes128’ algorithm to encrypt that plain password in coded format. i.e ‘6ac2b3b08ce481c8016ee2067ba44081’.
Decryption
The process of converting readable text to an unreadable format is called Decryption. The following method is used in Node.js to create Decryption.
const crypto = require('crypto');
const encrypt_password = '6ac2b3b08ce481c8016ee2067ba44081';
const decipher = crypto.createDecipher('aes128','a password');
var decrypted = decipher.update(encrypt_password,'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
Decipher is a class in which crypto.createDecipher()
is a method that creates an instance of that class. The instance of that class is used to transform encrypted data into a human-readable format.
In Example string '6ac2b3b08ce481c8016ee2067ba44081' is a encrypted password and using .update()
and .final()
method with ‘aes128’ algorithm to decrypt that encrypted password in readable format i.e 'crypto@123'
The dns
module that provides the underlying system name resolution and the DNS facility to look up. The DNS module is made up of an asynchronous network wrapper.
The most widely used features of the DNS module are:
-
dns.lookup(adress, options, callback)
The dns search method takes any website address as its first parameter and returns the corresponding first IPV4 or IPV6 record. The choice parameter can be an integer or an entity. If no options are provided, both IPV4 and IPV6 inputs are valid. The third parameter is the callback function.
-
dns.lookupservice(address, port, callback)
This function converts any physical address, such as "www.indiahires.com," to a set of record types. Record types are defined by the second "rrbyte" parameter. The third form is the callback function.
-
dns.getServers()
This feature returns an IP address string sequence, formatted according to rfc5952, which is currently designed for DNS resolution. If a custom port is used, a string will include a port section.
-
dns.setServers()
This function sets the IP address and port of the servers to be used for DNS resolution. The
dns.setServers()
method can not be called while the DNS query is in progress.
Callback is a function that is called when a task is completed, which helps prevent any kind of blockage, and a callback function enables another code to run in the meantime.
Callback is called when the task is completed and is an asynchronous function equivalent. Using the Callback principle, Node.js can process a large number of requests without waiting for any function to return the result that makes Node.js highly scalable. For example, in Node.js, when a function begins reading the file, it immediately returns the control to the execution environment so that the next command can be executed. When the file I / O is done, the callback feature will be called to prevent blocking or waiting for File I / O.
Example:
Code for reading a file asynchronously (non-blocking code) in Node.js. Create a text file file1.txt with the following content:
var fs = require("fs");
fs.readFile('file1.txt', function (ferr, filedata) {
if (ferr) return console.error(ferr);
console.log(filedata.toString());
});
console.log("End of Program execution");
Explanation:
The fs library is loaded to handle related file-system operations. The readFile()
function is asynchronous and the control returns immediately to the next command in the program while the function keeps running in the background. A callback function is passed which is called when the task running in the background is finished.
Passport is a middleware authentication for Node.js. As it is highly versatile and modular, Passport can be unobtrusively dropped into any Express-based web application. A robust range of techniques facilitates username and password protection, Facebook , Twitter, and more.
Passport recognizes that each program has specific criteria for authentication. Authentication mechanisms, known as strategies, are packaged as modules. Applications can choose which strategies to use without creating unnecessary dependencies.
By default, if authentication fails, Passport will respond with a 401 Unauthorized status, and no additional route handlers will be invoked. If authentication is successful, the next handler will be called and the req.user property will be assigned to the authenticated user.
-
Setting up Server using Express Framework.
First of all, we required all the module dependencies. After that we used middleware instances body-parser, cookie-parser and express-session. We used Mongodb to store database. You can see we loaded db file, so our connection will established, when we will start our server.
const express = require('express') const passport = require('passport') const db = require('./server/config/db') const bodyParser = require('body-parser') const expressSession = require('express-session') const cookieParser = require('cookie-parser') const app = express() const port = process.env.PORT || 3000 //use cookie parser to store data app.use(cookieParser()); app.use(expressSession({secret:'somesecrettokenhere'})); //load client folder //bodyparser to use for request and respnse and set limit in request body data app.use(bodyParser.urlencoded({ limit: '52428800', extended: true })); app.use(bodyParser.json({limit: '52428800'})); // Bootstrap passport config require('./server/config/passport')(passport); app.use(passport.initialize()); app.use(passport.session()); // Bootstrap routes require('./server/config/routes')(app, passport); app.listen(port); console.log('Express app started on port ' + port);
-
Setting up Database connection using Mongoose.
const Mongoose = require('mongoose'); const config = require('./config'); Mongoose.connect(config.db); const db = Mongoose.connection; db.on('error', console.error.bind(console, 'connection error')); db.once('open', function callback() { console.log("Connection with database succeeded."); }); exports.db = db;
-
Setting up Passport
const User = require('../user/user.server.model').User; const local = require('./passport/local'); module.exports = function (passport) { // serialize sessions passport.serializeUser(function(user, done) { done(null, user.id) }) passport.deserializeUser(function(id, done) { User.findOne({ _id: id }, function (err, user) { done(err, user) }) }) // use these strategies passport.use(local); };
Here we've used a local approach, you can add another facebook , twitter, etc. What's a serializer and deserializer passport? Serialize can decide which data from the user object will be stored in the session. For example, the result of the serializeUser method is attached to the session as
req.session.passport.user = {}
.In the first argument of deserialize method, you provide the same user object key that was provided to the done method in the serialize call. And with the aid of that key, the entire object is retrieved. This key is I d (the key may be any user object key, ie name, e-mail, etc.).
In the deserialize function, the key is matched to a database or any data resource. The object is attached as req.user to the request object. We used the local passport for local authentication by email (username) and password.
const LocalStrategy = require('passport-local').Strategy; const User = require('../../user/user.server.model').User; module.exports = new LocalStrategy({ usernameField: 'email', passwordField: 'password' }, function(email, password, done) { var options = { criteria: { email: email }, select: 'name email hashed_password salt' }; User.load(options, function (err, user) { if (err) return done(err) if (!user) { return done(null, false, { message: 'Unknown user' }); } if (!user.authenticate(password)) { return done(null, false, { message: 'Invalid password' }); } return done(null, user); }); } );
Once the load returns to our user object, the only thing left is to compare the Unknown User and the Password to see if there is a match. When there is a match, let the user in (by returning the user to the passport — return done(null, user)), unless we return an unauthorized error (by returning nothing to the passport — return done(null, wrong, {message:})). When to use the Passport Authentication path endpoint.
[…] Node JS Interview Questions […]