Node Callbacks and Events

Node JS Callbacks and Events

callbacks

 

CallBacks:

Callbacks are used for making asynchronous handling of functions. The process will run and do not block the next lines of execution and once the process is completed, it makes a callback action to perform actions of that data from the process.

Let’s say we have below pseudo code.

  • Run Process1() /-5 seconds
  • Run Process2() / -5 seconds
  • Run SomeCommads() /-2 seconds
  • Run SomeCommads() /-2 seconds

Here if we run synchronously, we can see the process1()  will take 5 seconds and after its completion, process2() takes another 5 seconds and then other commands taking 2 seconds each. This makes it slow as other processes are waiting for its execution.

Now lets simplify it using callbacks.

  • Run Process1() /
  • CallbackProcess1()
  • Run Process2() /
  • CallbackProcess1()
  • Run SomeCommads() /-2 seconds
  • Run SomeCommads() /-2 seconds

Now the Process1 is initiated with its callback and it will be executed once data is fetched. However, Process2 and other commands can run simultaneously. This will reduce the execution time.

Let’s see it in action for blocking and non-blocking code

Here is blocking code


const fs = require('fs')
//Process1
var data = fs.readFileSync('c:/test/file1.txt');
console.log(data.toString());
console.log("Done")

 

When we run this:

c:\test>node example6.js

Today is Sunday

Done

 

Now change it to asynchronous mode, where we call a callback function for the process and let the further statements to be executed.


const fs = require('fs')
//Process1
fs.readFile('c:/test/file1.txt', function (err, data) {
   if (err) return console.error(err);
   console.log(data.toString());
});
console.log("Done")

On running this :

c:\test>node example7.js

Done

Today is Sunday

 

The best part of asynchronous programming is that our code can do something else while waiting for the completion of a slow process.

A callback is a function passed as a parameter/argument which will be used for callback.

For example: In the above code, we can see the callback function passed as an argument.


fs.readFile('c:/test/file1.txt', function (err, data) {
   if (err) return console.error(err);
   console.log(data.toString());
}
);

Or in simple view


process1(file, callbackFunction)

function callbackFunction (error, data) {
  if (error) console.error('error!', error)
  else console.log('Process finished', data)
}

console.log('Process started')

 

CallBack Hell

Sometimes we end up with an ugly code where we use a lot of async calls and one callback inside another callback. This is referred to as callback hell and its hard to maintain and make changes.

Below is a sample code which looks like callback hell.


const process1 = function(data, callback) {
   process1(data, (error, id) => {
       if (error) {
           callback(error)
       } else {
           Process2(data, (error, path) => {
               if (error) {
                   callback(error)
				   console.log('Error in procdess2: ' + error)
               } else {
                   Process3(id, path, (error) => {
                       if (error) {
						console.log(error)                          
						  callback(error);
					   } else {
                           callback(null);
                       }
                   })
               }
           })
       }
   })
};

We can try to reduce callback hell by using the below techniques

  • Keep code shallow: Try to give names to each callback and avoid anonymous callback functions.
  • Common Functions: Try to create common functions and convert them to reusable modules. This will reduce code complexity and handlings.
  • Handle errors: Try to handle all possible error scenarios

 

Events

Objects in Node.js can fire events and action can be written based on that event.

All objects that emit events are members of EventEmitter class. These objects expose an eventEmitter.on() function that allows one or more functions to be attached to named events emitted by the object.

To use events, we need to import events module and create eventEmitter Object

 

Let’s understand by using the below code.


var events = require('events');
var eventEmitter = new events.EventEmitter();

var myHandler = function () {
  console.log('I am handling this event');
}

//Assign the event handler to an event:
eventEmitter.on('eventName', myHandler);

//Fire the event
eventEmitter.emit('eventName');

console.log("Something ....");

//Fire the event again
eventEmitter.emit('eventName');

On running this:

c:\test>node example7.js

I am handling this event

Something ….

I am handling this event

Here we can see that we have added a eventHandler – myHandler to the event – eventName and whenever eventName is fired, it gets executed.

 

Some Common methods to know in events

 

addListener(event, listener)

on(event, listener)

 

 

Adds a listener at the end of listeners array to the event
once(event, listener) One time execution of listener and then removed from event listeners
removeListener(event, listener)

 

Removed listener from event. If one listener is added multiple times, then needs to be removed multiple times.
removeAllListeners([event])

 

Remove all listeners
emit(event, [arg1], [arg2], […])

 

Emit the event

 

 

Frequently Asked Questions:

What is EventEmitter in Node.js?
All event emitting objects are instances of EventEmitter. Using eventEmitter.on(), we can attach listeners to the object and on emit of this event, the function /listener gets executed.

What is Event loop in Node.js
The event loop is what allows Node.js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.
Node.js application has many asynchronous functions and these functions have their own events and listeners attached to them. So whenever we call these asynchronous functions, say readFile, node.js setup callback function and continue for further code. On receiving file data, it executes the callback function and then all listeners will be executed one by one. This is referred to as event loop.

What is Event-driven programming in Node.Js?
It is like building an application based on to respond to events. If any event occurs, like a click of a button, then its callback function gets called to be executed. It follows mainly a publish-subscribe pattern.

What is a callback in Node.js?
It’s one of the main features of Node.js as it helps to make processes asynchronous. Here functions can define their callback functions which can be called after the task is completed.

What is callback hell in Node.js?
Callback hell is an outcome of heavily nested callbacks and it makes code hard to maintain and debug.

How can we prevent callback hell?
There are three main recommendations to prevent callback hell:
-Handle every single error
-Keep your code shallow
-Modularize/split code into small functions

What is the first parameter in callback calls?
It is the error object which is the first parameter in node callback functions. Its value is null or undefined if there is no error.
It is also referred to as an error-first callback.
For example :

fs.readFile(filePath, function(err, data) {
if (err) {
// handle the error first.
return console.log(err)
}
// Now work with data.
console.log(data)
})

Explain what is Reactor Pattern in Node.js?
Reactor Pattern is an idea of non-blocking I/O operations in Node.js.
We have a handler or callback function associated with I/O operation which gets called after data is fetched.
Here, we use demultiplexer which handles concurrency in non-blocking I/O mode and now the callback event is submitted to demultiplexer which collects and process each event in a queue.

What are the Promises?
Promises are an alternate way to handle callbacks in Node asynchronous calls. They offer simple ways and one can write multiple handlers for the function.

For example :
A callback handler

readFile(function(err, data) => {
if (error) {
return console.error(error)
}
console.log(data)
})

This can be done using promise:

let promise = readFile()
promise.then(console.log, console.error)

 

We can even chain this also:
readFile()
.then(readAnotherFile)
.then(doSomethingElse)
.then(…)

Leave a Comment

Your email address will not be published. Required fields are marked *