DEV Community

Cover image for Callback Hell in JavaScript: Escape the Pyramid of Doom
Ezhil Abinaya K
Ezhil Abinaya K

Posted on

Callback Hell in JavaScript: Escape the Pyramid of Doom

Callbacks in Javascript
In JavaScript, callbacks are functions that are passed as arguments from one function to another and are executed after the completion of a certain task. They are commonly used in asynchronous operations, such as reading files, making HTTP requests, or handling user input.

  • A function can accept another function as a parameter.
  • Callbacks allow one function to call another at a later time.
  • A callback function can execute after another function has finished.

How Do Callbacks Work in JavaScript?
JavaScript executes code line by line (synchronously), but sometimes we need to delay execution or wait for a task to complete before running the next function. Callbacks help achieve this by passing a function that is executed later.
Syntax:

function myFunction(param1, param2, callback) {
    // Do some work...
    // Call the callback function
    callback(result);
}
Enter fullscreen mode Exit fullscreen mode

Example

console.log("Start");

setTimeout(function () {
    console.log("Task Completed");
}, 2000);

console.log("End");
//Start
End
Task Completed
Enter fullscreen mode Exit fullscreen mode

Explanation:
Start is printed first. setTimeout sets times first .Javascript doesnt wait for the timer.End is printed immediately.After 2 seconds. the callback function runs and prints Task Completed.The function inside setTimeout is callback function because it is called later after the asynchronous task(timer) completes.

function greet(name, callback) {
    console.log("Hello " + name);
    callback();
}

function sayBye() {
    console.log("Goodbye!");
}

greet("Ezhil", sayBye);
//Hello Ezhil
Goodbye!
Enter fullscreen mode Exit fullscreen mode

sayBye is passed as callback. After greet() finishes printing"Hello Ezhil"it calls callback(), which executes sayBye().
Callback Hell
Callback Hell in JavaScript can be defined as the situation where we have nested callbacks(functions passed as arguments to other functions) which makes the code difficult to read and debug. The term "callback hell" describes the deep nesting of functions that can result in poor code readability and difficulty in debugging, especially when handling multiple asynchronous operations.
Problem with Callbacks
Callback Hell (Pyramid of Doom)
When multiple asynchronous operations depend on each other, callbacks get deeply nested, making the code hard to read and maintain.

const userId=101;
getUser(userId, (user) => {
    getOrders(user, (orders) => {
        processOrders(orders, (processed) => {
            sendEmail(processed, (confirmation) => {
                console.log("Order Processed:", confirmation);
            });
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

Explanation
First get the user details from userId.Then, we get the user orders.orders is processed. When processed is ready we sent an confirmation through email/phone.
The indentation increases with each level, making the code difficult to follow.
Error Handling in Nested Callbacks
Handling errors in nested callbacks is complex, as you must check for errors at each level manually.

function divide(a, b, callback) {
    if (b === 0) {
        callback(new Error("Cannot divide by zero"), null);
    } else {
        callback(null, a / b);
    }
}

function result(error, result) {
    if (error) {
        console.log("Error:", error.message);
    } else {
        console.log("Result:", result);
    }
}

divide(10, 2, result);
divide(10, 0, result);
//Result:5
Error:Cannot divide by zero
Enter fullscreen mode Exit fullscreen mode

Handling errors inside callbacks can complicate code readability.
Solution to Callback Hell

  • Promises
  • Async/await

Promises
Promises can help in avoiding the callback hell by providing the structured way to handle the asynchronous operations using the .then() method. Due to which the code becomes more readable by avoiding the deeply neseted callbacks.

  • Pending: The task is in the initial state.
  • Fulfilled: The task was completed successfully, and the result is available.
  • Rejected: The task failed, and an error is provided.
let checkEven = new Promise((resolve, reject) => {
    let number = 4;
    if (number % 2 === 0) resolve("The number is even!");
    else reject("The number is odd!");
});
checkEven
    .then((message) => console.log(message)) // On success
    .catch((error) => console.error(error)); // On failure
//The number is even!
Enter fullscreen mode Exit fullscreen mode

Syntax

let promise = new Promise((resolve, reject) => {
    // Perform async operation
    if (operationSuccessful) {
        resolve("Task successful");
    } else {
        reject("Task failed");
    }
});
Enter fullscreen mode Exit fullscreen mode
  • resolve(value): Marks the promise as fulfilled and provides a result.
  • reject(error): Marks the promise as rejected with an error.

Advanced Promise Methods
Promise.all() Method
Waits for all promises to resolve and returns their results as an array. If any promise is rejected, it immediately rejects.

Promise.all([
    Promise.resolve("Task 1 completed"),
    Promise.resolve("Task 2 completed"),
    Promise.reject("Task 3 failed")
])
    .then((results) => console.log(results))
    .catch((error) => console.error(error));
//Task 3 failed
Enter fullscreen mode Exit fullscreen mode

References
https://www.geeksforgeeks.org/javascript/what-to-understand-callback-and-callback-hell-in-javascript/
https://www.geeksforgeeks.org/javascript/javascript-promise/
https://www.geeksforgeeks.org/javascript/asynchronous-javascript/
https://www.geeksforgeeks.org/javascript/javascript-callbacks/

Top comments (2)

Collapse
 
dev_saravanan_journey profile image
Saravanan Lakshmanan

Nice and the banner deserves a special appreciation!🔥

Collapse
 
ezhil_abinayak_e38eec8fb profile image
Ezhil Abinaya K

Adadeyyy!! Thank u so much for ur feedback 💥