DEV Community

Cover image for Callback, Callback Hell & Promise in JavaScript
Saravanan Lakshmanan
Saravanan Lakshmanan

Posted on

Callback, Callback Hell & Promise in JavaScript

What is a Callback?

A callback is simply a function passed as an argument to another function so that it can be executed later.

Example:

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

function processUser(callback) {
    callback("Saravanan");
}

processUser(greet);
Enter fullscreen mode Exit fullscreen mode

Output

Hello Saravanan
Enter fullscreen mode Exit fullscreen mode

Here, greet is the callback function.


Why do we need callbacks?

Some tasks take time to complete.

For example:

  • Downloading data from a server
  • Reading a file
  • Waiting for a timer
  • Fetching API data

JavaScript doesn't stop the entire program while waiting.

Instead, it says:

"Continue doing other work. When this task finishes, I'll call the callback."

Example:

console.log("Start");

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

console.log("End");
Enter fullscreen mode Exit fullscreen mode

Output

Start
End
Task Completed
Enter fullscreen mode Exit fullscreen mode

Notice that JavaScript didn't wait for 2 seconds before printing End.


The Problem: Callback Hell

Imagine we're building software using the SDLC process.

The order should be:

Planning
↓
Design
↓
Development
↓
Testing
↓
Deployment
Enter fullscreen mode Exit fullscreen mode

Using callbacks:

function planning(callback) {
    setTimeout(() => {
        console.log("Planning Completed");
        callback();
    }, 1000);
}

function design(callback) {
    setTimeout(() => {
        console.log("Design Completed");
        callback();
    }, 1000);
}

function development(callback) {
    setTimeout(() => {
        console.log("Development Completed");
        callback();
    }, 1000);
}

function testing(callback) {
    setTimeout(() => {
        console.log("Testing Completed");
        callback();
    }, 1000);
}

function deploy() {
    console.log("Deployment Completed");
}

planning(() => {
    design(() => {
        development(() => {
            testing(() => {
                deploy();
            });
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

Although the program works, there's a problem.

The code keeps moving further to the right.

planning(
    design(
        development(
            testing(
                deploy()
            )
        )
    )
)
Enter fullscreen mode Exit fullscreen mode

This deeply nested structure is called Callback Hell.

Problems with Callback Hell:

  • Difficult to read
  • Difficult to debug
  • Difficult to maintain
  • Becomes messy as the project grows

Solution: Promise

A Promise represents the result of an asynchronous operation.

It can be in one of three states:

  • Pending
  • Fulfilled (Resolved)
  • Rejected

Creating a Promise:

const planning = () => {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log("Planning Completed");
            resolve();
        }, 1000);
    });
};
Enter fullscreen mode Exit fullscreen mode

The Promise either calls:

resolve();
Enter fullscreen mode Exit fullscreen mode

when successful,

or

reject();
Enter fullscreen mode Exit fullscreen mode

when something goes wrong.


Promise Chaining

Now we can execute tasks one after another without nesting.

planning()
    .then(() => design())
    .then(() => development())
    .then(() => testing())
    .then(() => deploy())
    .catch(() => console.log("Something went wrong."));
Enter fullscreen mode Exit fullscreen mode

This code is much easier to read.

It clearly says:

Planning
→ Design
→ Development
→ Testing
→ Deploy
Enter fullscreen mode Exit fullscreen mode

Even Cleaner: async/await

JavaScript introduced async and await to make Promise-based code look more like normal synchronous code.

async function SDLC() {
    try {
        await planning();
        await design();
        await development();
        await testing();
        await deploy();
    } catch (error) {
        console.log(error);
    }
}

SDLC();
Enter fullscreen mode Exit fullscreen mode

This is usually easier to understand because the steps appear in the same order they execute.


Callback Hell vs Promise

Callback Hell Promise
Deeply nested code Flat and readable code
Hard to maintain Easy to maintain
Difficult error handling Centralized error handling using .catch()
Less readable as the project grows Easier to understand and extend

References:
https://www.w3schools.com/js/js_promise.asp
https://www.geeksforgeeks.org/javascript/javascript-promise/

Top comments (1)

Collapse
 
raja_b_0c9d242e2c26cf063b profile image
Raja B

Mr saravanan

What is a callback function?

What is the Event Loop in JavaScript?