Callback Hell(Pyramid of the Doom):

Callback Hell(Pyramid of the Doom):

Table of contents

Javascript is a synchronous single-threaded language and it can just do one task at a time whatever code you give to Javascript will be quickly executed by the Javascript engine. It does not wait for anything.

Asynchronous JavaScript

The asynchronous style of the programming focuses more on improving the performance of the application and callbacks can also be used in such situations. The asynchronous behaviour of JavaScript can be explained using the setTimeout function as shown in the code below.

function display() {
console.log("Timer displayed after 1 second.")
}
setTimeout(display, 1000);

The function has to wait for 1s for its execution.

One more example:

Suppose we are building our e-commerce website and the e-commerce website can't exist without a cart. Once the items into the cart, know how the e-commerce site works. So first we need to create an order and then proceed to payment. Now we will create two API's one is createOrder API, which creates order and another API is proceedToPayment . Once the order is created then only we proceed to payment. There is a dependency between them so how do we manage that dependency in our code because this is an async operation? So here callback comes into the picture. The callback can help us write code for this kind of behaviour.

const cart = ["Shoes", "Watches", "Earphones"];
//Async Operation
api.createOrder();
api.proceedToPayment();

Callback:

In JavaScript, everything (strings, arrays, functions) is considered an object. Hence, the concept of callbacks lets us pass functions as arguments to another function which will be executed later within the outer function.

const cart = ["Shoes", "Watches", "Earphones"];
//Async Operation
api.createOrder();

function(){
api.proceedToPayment();
};

Now, we will wrap proceedToPayment() API inside the callback function. Now we will take this callback function to createOrder() API and pass it along with the cart item as an argument.

const cart = ["Shoes", "Watches", "Earphones"];
//Async Operation
api.createOrder(cart, function(){
api.proceedToPayment()
});

When the javascript engine executes the above piece of code it will just call the createOrder() API . Now this is the responsibility of createOrder() API to create an order and then call the proceedToPayment() function back. That way we can handle async operations in JavaScript.

Now after the payment is successful we need to show the summary page of the payment and for that, we have another API showOrderSummary() . We have to call this API only after we have done with the payment API. Now we will pass this callback function showOrderSummary() to the proceedToPayment() API. Now it is the responsibility of proceedToPayment() API to complete the payment and call showOrderSummary() function back.

const cart = ["Shoes", "Watches", "Earphones"];
//Async Operation
api.createOrder(cart, function(){
    api.proceedToPayment(function() {
        api.showOrderSummary()
})
});

That's how we manage dependency between this whole flow which happens one after the other but here is a big problem we can face. So now we have created an order, we have done the payment, and we have shown the order summary and now we want to update the wallet and now we will pass this updateWallet() API to showOrderSummary() .

const cart = ["Shoes", "Watches", "Earphones"];
//Async Operation
api.createOrder(cart, function(){
    api.proceedToPayment(function() {
        api.showOrderSummary(function() {
            api.updateWallet()
    });
  });
});

So when there are a lot of APIs and APIs are dependent on one after the other, what happens is we end up falling into this callback hell.

  • Callback hell is a phenomenon that happens when multiple callbacks are nested on top of each other. The two common ways of escaping the callback here are by using promises and async/await.

  • It makes the code very difficult to understand and maintain.

Inversion of Control:*

api.createOrder(cart, function(){
    api.proceedToPayment()
  });
});

Now what is happening in the above code is we are creating an order. What we are doing here is we take the callback function and giving it to the createOrder() API. Now as a developer, we are expecting that createOrder() function at some point in time will create an order that will call our function back but this is very risky.

proceedToPayment() is an important part of our code. Here we gave control of our program to createOrder() API. Now it is the responsibility of createOrder() API to call our function back and we are blindly trusting create order API. There could be a lot of bugs inside the createOrder() API. What if our callback function is called twice? What if our callback function is never called? This is a very important and risky thing which we need to take care of.

Issues with callbacks:

1) Callback Hell

2) Inversion Of Control