Table of contents
1.
Introduction
2.
What is Callback in Javascript?
2.1.
Javascript
2.2.
Synchronous Programming
2.3.
Javascript
2.4.
Asynchronous Programming
2.5.
Javascript
3.
What is Callback Hell?
3.1.
Javascript
3.2.
Javascript
4.
Promises
4.1.
Javascript
5.
Async/Await
5.1.
Javascript
6.
Escaping the Callback Hell
7.
Frequently Asked Questions
7.1.
Q. Why is callback hell bad?
7.2.
Q. Is JS synchronous or asynchronous?
7.3.
Q. What is callback() in JavaScript?
7.4.
Q. What are the disadvantages of callback hell?
8.
Conclusion
Last Updated: Aug 25, 2024
Medium

Callback Hell in Javascript

Author Sohail Ali
1 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Hi Coders! As you know that we can pass an argument to a function, right? But Javascript also allows users to pass functions as an argument to some other function. This property of Javascript is known as ‘Callback’. Callback hell in Javascript occurs when multiple callbacks are nested inside each other, leads to create a complex and hard-to-manage code. Which makes it difficult to follow the flow of the program.

Callback Hell in JavaScript

In this blog, we are going to learn all about Callback hell in Javascript with some examples. So let’s start learning!

What is Callback in Javascript?

The Callback in Javascript is a type of function that is passed as an argument to some other function. Every entity (array, string, function) is treated as an object in Javascript. Thus the user is able to pass functions as an argument. 

Let us now see a simple example to understand the Callback function better.

  • Javascript

Javascript

function printHello(){
console.log("Hello Ninjas!");
}

function printMessage(){
console.log("I'm a pro coder!")
}

function helper(callback){

// Calling the callback() function
callback();
}

// First call
helper(printHello);

// Second call
helper(printMessage);
You can also try this code with Online Javascript Compiler
Run Code


Output

Callback output

Explanation

Let’s now discuss the execution of the above example of Callback hell in Javascript.

  • First, the execution command goes to the helper function with printHello as a parameter. 
     
  • This helper function calls the printHello function inside itself using Callback. After that, the ‘Hello Ninjas!’ message gets printed, and the execution command goes again to the helper function with printMessage as a parameter.
     
  • Now this time, the helper function calls the printMessage function inside it, and the second print statement gets printed.
     

From the above example, we can conclude that printHello() and printMessage() are Callback functions that are passed as an argument to the helper() function.

Synchronous Programming

In this programming method, the programmer can only perform a single task at a time. We cannot start another task until the first is completed. As the name itself suggest, synchronous means in sequence. This method of programming is also called blocking code, as one process needs to wait for the completion of another. 

In the synchronous method, Callback is executed whenever the calling functions make a call to it. Let’s now see an example to understand Callback in the synchronous method.

  • Javascript

Javascript

function print_message(){
console.log("Welcome to my blog viewers ")
}

function Caller_function(callback){

console.log("Before calling the callback function");

// Calling the callback() function
callback();
 
console.log("After calling the callback function")
}

// Making the call
Caller_function(print_message);
You can also try this code with Online Javascript Compiler
Run Code


Output

Synchronous output

Explanation

In the above example, initially, the execution command goes to the Caller_function, and the first print statement gets printed. Later, Callback() function gets executed, and we get our second print statement. This way, the program flow is in a sequence in the synchronous method. 

Asynchronous Programming

In this method of programming, the users do not need to wait for the main thread to be completed. Instead, parallel processing is possible in the asynchronous method. Thus the user can execute a current task without worrying about the completion of the previous one. Due to this behaviour, an asynchronous method is called a non-blocking code. 

Let us now understand this asynchronous way of programming with an example.

  • Javascript

Javascript

function print_message(){
console.log("Welcome to my blog viewers ")
}

function Caller_function(callback){

console.log("Before calling the callback function");

// Calling the callback function in setTimeout
setTimeout(callback, 3000);

console.log("After calling the callback function")
}

// Making the call
Caller_function(print_message);
You can also try this code with Online Javascript Compiler
Run Code


Output

Asynchronous output

Explanation

In the above example, we notice that our program didn’t wait for the Callback function to finish. Instead, it executed the next statements after the Callback, and parallelly the Callback function completed its execution. Here the setTimeout() method will halt the callback execution for exactly 3 seconds.

You can read more about the setTimeout() method here - setTimeout jQuery.

What is Callback Hell?

Callback hell is a phenomenon where a Callback is called inside another Callback. It is the nesting of multiple Callbacks inside a function. If you look at the design of the code, it seems just like a pyramid. Thus the Callback hell is also referred to as the ‘Pyramid of Doom’.

Callback hell structurally is just a nesting of function calls inside a function. But, it becomes difficult to understand and keep track of the nesting once the size of the nesting is increased.

The below code will give you an idea of why this phenomenon is labelled as Hell/Doom.

  • Javascript

Javascript

function print(i){
window.alert("This is call number "+i);
}

function fun1(callback){
setTimeout(()=>{

let i = 1 ;
    callback(i); i++ ;
    setTimeout(()=>{
   
      callback(i); i++;
      setTimeout(()=>{
      
        callback(i); i++ ;
        setTimeout(()=>{
        
          callback(i); i++ ;
          setTimeout(()=>{
          
            callback(i); i++ ;
            // .... and so on
           
          }, 800)
        }, 700)
      }, 500)
    }, 300)
}, 100)
}

// Calling fun1 with print function as parameter
fun1(print);
You can also try this code with Online Javascript Compiler
Run Code


Output

Callback hell output

Explanation

In the above example, we nested and called the Callback inside the setTimeout() method. The Callback will execute all calls to the print() function in its specified time.

Here, we can see the complexity of calling the Callback method in a nesting method. The code becomes difficult to comprehend and debug.

Let’s look at another example. Suppose we want to check whether a user made a successful payment or not. If he did, then terminate the program; else, run the program till the user does not make payment. 

Below is the code to implement it using Callback:

  • Javascript

Javascript

var DidPayment = true;

function message(){
console.log("Payment Successful");
}

function UserPayment(DidPayment, callback){

if(DidPayment){
    callback();
  }else{
    UserPayment();
    if(DidPayment){
      callback();
    }else{
      UserPayment();
      if(Didpayment){
        callback();
      }else{
        UserPayment();
        //... And so on
      }
    }
  }
}

// Making the call
UserPayment(DidPayment, message);
You can also try this code with Online Javascript Compiler
Run Code


Here, if the user successfully made the payment, then the payment completion message is printed. Otherwise, we will execute the program until he doesn’t make a payment. Thus we will get an output like the one given below:

Async/Await output

But there’s a catch if he does not complete the payment, then we will get stuck into an infinite loop where UserPayment function is called continuously. This will result in a range error because the maximum call stack size will exceed. So how can we overcome this problem?

We can avoid this problem using a few methods like Promises, async/await, and Partitioning bigger functions into smaller ones.

Promises

In Javascript, promises can be used in place of Callbacks for asynchronous tasks. Promises make code more readable and easy to comprehend.

You can read this article to learn more about promises- Understanding Javascript Promises.

Once you know the basic methods of promises, let’s now look at our previous example and solve the issue using promises.

After using promises, our code will look like this:

  • Javascript

Javascript

var DidPayment = false ;

var promise = new Promise( (resolve, reject) =>{

if(Didpayment){
  // Calling the resolve method
  resolve();
}else{
  // Calling the reject method
reject();
 }

});

promise.then ( () =>{
console.log("User Payment Successful!");
}).catch(()=>{
  console.log("User Payment Canceled");
})
You can also try this code with Online Javascript Compiler
Run Code


Output

Promises output

Explanation

In the above example, the else statement is executed, and the reject() method of promise notifies that the user cancelled the payment. Similarly, if the user makes a successful payment, the resolve() method will notify about payment completion. Thus we were able to solve the problem in Callback.

Async/Await

This is another alternative to avoid Callback Hell. This method is often called a ‘syntactic sugar on top of promises’. It eliminates the need of the .then() and .catch() methods of promises. All you have to do is put an async word before the function, which we want to make a promise.

Let’s understand this method using the same example.

  • Javascript

Javascript

var DidPayment = true;

async function UserPayment() {
   try {
       if (DidPayment) {
        console.log("Payment Successful");
       }
   } catch (err) {
       console.log("Payment cancel");
   }
}

// Making the function call
UserPayment();
You can also try this code with Online Javascript Compiler
Run Code


Output

Async/Await output

Explanation

In the above example, we can observe that simply putting an ‘async’ word before the name of the function makes it behave like a promise in Javascript. So using an async, our code becomes even more readable, and at the same time, we are able to avoid Callback hell.

Note: We don’t have a catch() method here, like in the promises. Therefore we use a try-catch block in the code.

Wooh! Finally, we were able to stop the Callback hell in Javascript completely. 

Escaping the Callback Hell

Escaping callback hell (also known as "callback pyramid") is crucial for writing clean, readable, and maintainable JavaScript code. Callback hell occurs when you have multiple nested callbacks within callbacks, leading to code that is hard to understand and prone to errors.

Here are some strategies to escape callback hell:

  • Use Promises: Promises provide a more structured way to handle asynchronous operations. You can chain .then() and .catch() methods to create a linear flow of code instead of deeply nested callbacks.
     
  • Async/Await: async/await is even more readable than promises. It allows you to write asynchronous code that looks like synchronous code, making it easier to understand.
     
  • Modularization: Break your code into smaller, reusable functions. This reduces the nesting level and makes your code more organized and easier to comprehend.
     
  • Named Functions: Use named functions instead of anonymous functions for callbacks. Named functions provide clarity and make your code more readable.

Frequently Asked Questions

Q. Why is callback hell bad?

Callback hell, or deeply nested callbacks, is bad because it makes code hard to read and maintain. It becomes complex and error-prone, leading to debugging difficulties and reduced code quality.

Q. Is JS synchronous or asynchronous?

JavaScript (JS) is asynchronous by nature. It utilizes non-blocking operations, allowing code to continue executing while waiting for asynchronous tasks like file I/O or network requests to complete. This feature enhances responsiveness and performance, especially in web development contexts.

Q. What is callback() in JavaScript?

A callback in JavaScript is a function passed into another function as an argument to be executed later, supporting asynchronous operations.

Q. What are the disadvantages of callback hell?

Callback hell leads to nested and complex code that is hard to read and maintain, often resulting in error-prone and tangled program logic.

Refer to know about:   jquery ajax

Conclusion

This article discusses the Callback and Callback hell in Javascript. We discussed various methods using which we can avoid Callback hell in Javascript. We hope this blog has helped you enhance your knowledge of Callback hell in Javascript. If you want to learn more, then check out our articles.

And many more on our platform Coding Ninjas Studio.

Refer to our Guided Path to upskill yourself in DSACompetitive ProgrammingJavaScriptSystem Design, and many more! If you want to test your coding ability, you may check out the mock test series and participate in the contests hosted on Coding Ninjas Studio!

But suppose you have just started your learning process and are looking for questions from tech giants like Amazon, Microsoft, Uber, etc. In that case, you must look at the problemsinterview experiences, and interview bundles for placement preparations.

However, you may consider our paid courses to give your career an edge over others!

Live masterclass