Node Js Callback Hell
There are few general prerequisites :
- Node.js must be installed on your development system whether it be windows, macOS, or Linux.
Asynchronous Programming in Node.js
If API calls were performed in a synchronous manner, then the browser would not be able to maintain interactive behavior (like taking any kind of input from the user, like scrolling, mouse click, or button press) until that API request is complete. This is known as blocking nature. In contrast, asynchronous programming is a technique that ensures non-blocking code execution.
Example: Suppose we want to download an image from the internet, then edit the downloaded image (cropping or something else) and then save the edited image on the hard disk of our system.
The above process can be defined using three simple steps:
- Downloading the image from the internet.
- Editing the image.
- Saving the edited image on the hard disk.
All the steps are dependent on the previous steps; hence we need asynchronous programming in Nodejs. This can be achieved by using callbacks in Node.js.
What is a Callback?
A simple example of a function that everyone must have used must be,
Simplifying the above example:-
Now we can clearly see that the clicked function is a parameter to the addEventListener function and is a callback. Also, the function that takes another function as an argument is called a higher-order function.
Syntactic Code Example of a Higher-Order Function and a Callback
The callback functions are used a lot in asynchronous Node.js, but it does not mean that callbacks are not used in synchronous programming.
Callbacks in Synchronous Programming
In the above example, we are using the array.map() method, which takes in a callback as an argument.
As the function traverses through the given array, each element of the array will be passed in as a parameter into our callback function. The callback function is passed in the map function, intended to be used later when our code executes.
When our code executes, the array.map() function will use our callback function for every single index in our array. We defined what we want the callback function to do, which in this example is to multiply 10 to every argument(in the above case, the number in our array at the current iteration) we pass into the callback function, which is all happening synchronously.
Callbacks in Asynchronous Programming
An example of an asynchronous use of callbacks is when we use the setTimeout() function. setTimeout takes in two arguments, a callback function and how long to delay in milliseconds before running that callback function.
In this above example, we have passed a callback function as the second argument to foodOrder, allowing us to use it in our asynchronous setTimeout function. This callback is used for logging our foodData in the console after 5 seconds.
What is Callback Hell in NodeJs?
Callback functions are a useful way to confirm the delayed execution of a function until another function completes its execution and returns with data. However, we may need to nest callbacks inside callbacks, and this nested nature of callbacks can scale horizontally and become unreadable as well as messy if you have a lot of consecutive asynchronous requests that rely on each other. This nesting of callbacks is known as node js callback hell or the Pyramid of Doom.
Here is an example of nested callbacks:
In the above code, each new setTimeout() is nested inside a higher order function, creating a pyramid of doom or node js callback hell.
Example of Callback Hell in NodeJs
An example showing how node js callback hell is constructed, let us imagine we’re trying to make a burger. To make a burger, we need to follow these steps:
- Get ingredients (we’re gonna assume it’s veg burger)
- Cook the Aloo patty
- Get burger buns
- Put the cooked patty and vegies between the buns
- Serve the burger
- To make the burger, we have to get the ingredients first.
- Now we need to instruct the helper to cook the patty. And after that get the buns.
- After we get the buns, we need to put the patty between the buns.
- Finally, we can serve the burger! But we can’t return burger from makeBurger because it’s asynchronous. We need to accept a callback to serve the burger.
A working and running example of callback hell :
The function and second request to asynchronousFunc are executed because a parameter are passed. The third request to asynchronousFunc is passed with a null parameter. Hence this request throws an error, which affects all the other functions nested inside this one. Hence the executions stops at this request.
Ways to Avoid NodeJs Callback Hell In
Let us take our makeBurger example again and try to avoid callback hell using the following solutions:
The makeBurger() callback hell in Nodejs is simple to understand to us. We can read it. It just doesn’t look readable and straightforward.
If someone is reading makeBurger() for the first time, they may think, “What is the need for so many nested callbacks to make a simple function?”.
Now the readability of the program has been increased due to the comments.
Split Functions into Smaller Functions
Let us write the step-by-step imperative code of all the functions under makeBurger().
For getIngridients(), the first callback, we have to go to the fridge and get the ingredients like tomatoes, potatoes, and onions. Suppose there are fridges on the top and bottom floor of the kitchen. We need to go to the bottom fridge.
To cook potatoes, we need to wash and peel the potatoes and then fry those potatoes, and wait for 10-20 minutes.
Similarly, we can write other functions also under the makeBurger() function, but this will lead to a large codebase.
We can use promises instead to improve the syntax of the makeBurger(). Promises can make callback hell in the Node.js program much easier to manage and read. Instead of the nested callbacks code you saw in the original example, you will have the following code:
Further simplifying the above code,
We can observe that the above code is much more easier to read and manage than the original example. Now to convert the callback-based code into promise-based code, we need to create a new promise for each callback. Then we need to resolve the promise if the callback is successfully executed or reject the promise if the callback fails.
In Node.js, each of the other functions that contain a callback can be written using the same syntax.
4. Using Async/ await
With Async/ await functions, we can write makeBurger() as if it is synchronous in nature.
One improvement can be made to the makeBurger() method here. You can likely get two helpers to getBuns and getPotatoes at the exact same time. This means you can await them both with Promise.all().
Take your coding skills to new heights with our Free Node JS course. Join today and learn to create efficient and high-performance backend systems.
- Asynchronous nature can be achieved with the help of callbacks in Node.js.
- Callbacks are used in some synchronous methods of Node.js like array.map().
- Callbacks are basically methods that are passed as the parameters to the other function.
- Functions that take other functions as a parameter are known as Higher Order functions.
- Nesting of callbacks can lead to an unreadable and not easy to manageable codebase commonly known as callback hell in Node.js or pyramid of doom.
- Node js callback hell can be avoided using Promises and async / await.
- Splitting of the functions and by writing comments can also be used to avoid callback hell in Node js.