Callback Hell in NodeJS !!! && The ways to come out of that Hell !!

Callback Hell in NodeJS !!! && The ways to come out of that Hell !!

Featured on daily.dev

Node.JS, nowadays most trending tech to build the backend APIs. Yes it's awesome but, not sooooooo easy that you won't stuck in any code issues. Most common issue that developers face during the development is "Callback Hell". Now you might think, what the hell this "Hell" is doing in programming language. Let's move on and dig up on what is this exactly....

To start with this callback hell, you should first know about synchronous and asynchronous JavaScript.

Synchronous JavaScript, What it is ?

In Synchronous JavaScript only one process is executed at a time. Now you might think why one process at a time. Hope you remember that in our last blog we discussed - NodeJS is single threaded. As only one process can be executed at a time, all other remaining processes/operations are on hold until you get the response from the current process in execution. Every process runs in synch in a queue.

What is Asynchronous JavaScript ?

  • The term asynchronous refers to two or more processes or events existing or happening at the same time (or multiple related things happening without waiting for the previous one to complete).
  • Some functions in JavaScript requires AJAX because the response from some functions are not immediate. It takes some time and the next operation cannot start immediately. It has to wait for the function to finish in the background. In such cases, the callbacks need to be asynchronous.
  • So simply you can say that run multiple operations in parallel without waiting for other. This is the importance of NodeJS. Run as many as processes you wish. But yes keep in mind, don't use this for running processes that require high computation power.

Let's get into the world of Callback ...

You can take Callback as an asynchronous equivalent for a function. Each callback is called at the completion of particular task related to that callback. Mostly all APIs of NodeJS are written in a way to supports callbacks.

Example : suppose you created a function which will read content of a file and return the same. But what if that file is very large to read ? You won't wish to wait for such long keeping other operations in wait state right. So using callback when the function start reading file, it returns the control to execution environment immediately so that the next instruction can be executed. On completion of the read operation, results can be stored or processed accordingly.

- Synchronous Program

var fs = require("fs");  
var data = fs.readFileSync('fileToRead.txt');  
console.log(data.toString()); 
console.log("!!!!! Hello Mate Hope you already got the file content above !!!");

Output:

synchout.png

- Asynchronous Program (Using callback)

var fs = require("fs");  
fs.readFile('fileToRead.txt', function (err, data) {  
    if (err) return console.error(err);  
    console.log(data.toString());  
});  
console.log("!!!!! Hello Mate, Read operation is still in progress. You should get the file content soon !!!");

Output:

asyncout.png

I hope, you are now clear with the concept of Synchronous and Asynchronous. Now we can move on with the focus area of this blog i.e. "Callback Hell".

What is Callback Hell ?

Callback hell is a phenomenon that irritates a JavaScript developer when he tries to execute multiple asynchronous operations one after the other.

Sometimes callback hell is also termed as Pyramid of Doom

Let’s have a look at an example of what we call callback hell -

doSomething(param1, param2, function(err, paramx){
    doMore(paramx, function(err, result){
        insertRow(result, function(err){
            yetAnotherOperation(someparameter, function(s){
                somethingElse(function(x){
                });
            });
        });
    });
});

Can you be sure when this function in above code named "somethingElse" will execute ? No one can say that. what if the result from function doSomething i.e. paramx which is used as an argument for insertRow has some issues ? Then the other nested functions will of course generate erroneous results. These nested set of callbacks is termed as callback.

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 making the code unmanageable.

What can be done to avoid this conditions of callback Hell ?

Using Promises :

  • Promises are alternative to callbacks when 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.

What does this Promise looks like .....

var outputPromise = getInputPromise().then(function (input) {
    //handle success
}, function (error) {
    //handle error
});

We can also chain up the promises which can be an alternative to nested callbacks. Check the Example below -

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);
});

Using Async Await :

Async Await feature makes asynchronous nodejs code look like it’s synchronous. This has only been possible because of the reintroduction of promises into node.js.

NOTE -- Async-Await only works with functions that return a promise.

Using async-await in Node.js is the best way to avoid callback hell. Let’s understand it with an example -

const getSomeNumber= function(){
    return new Promise((resolve, reject)=>{
        setTimeout(() => {
            resolve(Math.floor(Math.random() * 10));
        }, 1000);
    });
}

const addNumbers = async function(){
    const result= await getSomeNumber() + await getSomeNumber();
    console.log(result);
}

addNumbers();
  • If you see above we have a function that returns us a number after 1 sec. This function returns a promise.
  • Using await keyword we tell javascript to wait for the result before moving forward. But this await keyword only works within functions that are declared as async.
  • When we declare a function as async, we are telling javascript to suspend the execution until the result arrives whenever it encounter the await keyword.

NOTE -- If you declare a function as async , that function will return a Promise.

This two solutions would be great to solve the problem of callback hell in an utmost easiest way. It will be great if you practice the same and debug through the code to get more practical clarity.

Till now I have used these two options to tackle the problem of callback hell. If you find any more easier way to do so please add the same in comment section :).

Thank you for Reading this Blog !!

Hope you loved this. Feel free to add your comments in the below comment section. Your comments are an opportunity for me to learn and improve.

You can reach out to me on Linkedin & Twitter

Also please don't forget to read my other Blogs.

Did you find this article valuable?

Support Learn with HJ by becoming a sponsor. Any amount is appreciated!