DEV Community

Jenil
Jenil

Posted on

Callbacks, Callback Hell, Promises, Async/Await

“Coding can sometimes feel like a suspenseful movie - full of unexpected twists and turns. But what if you could make your code flow as smoothly as a well-directed scene? Welcome to the world of callbacks, promises, and async/await!”

1. Callback

A callback is a function that you pass as an argument to another function, which is then executed after the completion of that function. Think of it like this: You order a movie ticket online, and you tell them to send you an email (the callback function) when the ticket is ready.

Example:
Imagine you're ordering a ticket for the movie "Spider-Man 4" online:

function orderTicket(movie, callback) {
    console.log(`Ordering ticket for ${movie}...`);
    // Simulate a delay with setTimeout
    setTimeout(() => {
        console.log('Ticket ordered successfully!');
        callback();  // Notify when the ticket is ready
    }, 2000);
}

function notifyUser() {
    console.log('Your ticket is ready! Enjoy the movie!');
}

orderTicket('Spider-Man 4', notifyUser);
Enter fullscreen mode Exit fullscreen mode

Output:

Ordering ticket for Spider-Man 4...
Ticket ordered successfully!
Your ticket is ready! Enjoy the movie!
Enter fullscreen mode Exit fullscreen mode

Here, notifyUser is the callback function that gets called after the ticket is ordered.

2. Callback Hell

Callback hell happens when you have several callbacks nested inside each other, making the code hard to read and maintain. It looks like a pyramid or a staircase, and it’s difficult to follow what’s happening.

Example:
Now imagine you want to do multiple things, like ordering tickets, getting popcorn, and finding your seat, all in sequence:

function orderTicket(movie, callback) {
    console.log(`Ordering ticket for ${movie}...`);
    setTimeout(() => {
        console.log('Ticket ordered successfully!');
        callback();
    }, 2000);
}

function getPopcorn(callback) {
    console.log('Getting popcorn...');
    setTimeout(() => {
        console.log('Popcorn ready!');
        callback();
    }, 1000);
}

function findSeat(callback) {
    console.log('Finding your seat...');
    setTimeout(() => {
        console.log('Seat found!');
        callback();
    }, 1500);
}

orderTicket('Spider-Man 4', function() {
    getPopcorn(function() {
        findSeat(function() {
            console.log('All set! Enjoy the movie!');
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

Output:

Ordering ticket for Spider-Man 4...
Ticket ordered successfully!
Getting popcorn...
Popcorn ready!
Finding your seat...
Seat found!
All set! Enjoy the movie!
Enter fullscreen mode Exit fullscreen mode

This is callback hell: you can see how the code becomes more nested and harder to read.

3. Promise

A promise is an object that represents the eventual completion (or failure) of an asynchronous operation. It allows you to write cleaner code and handle asynchronous tasks more easily without falling into callback hell.

Example:
Let’s simplify the above example using promises

function orderTicket(movie) {
    return new Promise((resolve) => {
        console.log(`Ordering ticket for ${movie}...`);
        setTimeout(() => {
            console.log('Ticket ordered successfully!');
            resolve();
        }, 2000);
    });
}

function getPopcorn() {
    return new Promise((resolve) => {
        console.log('Getting popcorn...');
        setTimeout(() => {
            console.log('Popcorn ready!');
            resolve();
        }, 1000);
    });
}

function findSeat() {
    return new Promise((resolve) => {
        console.log('Finding your seat...');
        setTimeout(() => {
            console.log('Seat found!');
            resolve();
        }, 1500);
    });
}

orderTicket('Spider-Man 4')
    .then(getPopcorn)
    .then(findSeat)
    .then(() => {
        console.log('All set! Enjoy the movie!');
    });
Enter fullscreen mode Exit fullscreen mode

Output:

Ordering ticket for Spider-Man 4...
Ticket ordered successfully!
Getting popcorn...
Popcorn ready!
Finding your seat...
Seat found!
All set! Enjoy the movie!
Enter fullscreen mode Exit fullscreen mode

Promises make the code easier to read by chaining .then() methods, avoiding the nesting problem.

4. Async/Await

Async/await is a modern syntax that allows you to write asynchronous code that looks and behaves like synchronous code. It’s built on top of promises and makes the code even cleaner and easier to understand.

Example:
Let’s use async/await to handle the same scenario

function orderTicket(movie) {
    return new Promise((resolve) => {
        console.log(`Ordering ticket for ${movie}...`);
        setTimeout(() => {
            console.log('Ticket ordered successfully!');
            resolve();
        }, 2000);
    });
}

function getPopcorn() {
    return new Promise((resolve) => {
        console.log('Getting popcorn...');
        setTimeout(() => {
            console.log('Popcorn ready!');
            resolve();
        }, 1000);
    });
}

function findSeat() {
    return new Promise((resolve) => {
        console.log('Finding your seat...');
        setTimeout(() => {
            console.log('Seat found!');
            resolve();
        }, 1500);
    });
}

async function watchMovie() {
    await orderTicket('Spider-Man 4');
    await getPopcorn();
    await findSeat();
    console.log('All set! Enjoy the movie!');
}

watchMovie();
Enter fullscreen mode Exit fullscreen mode

Output:

Ordering ticket for Spider-Man 4...
Ticket ordered successfully!
Getting popcorn...
Popcorn ready!
Finding your seat...
Seat found!
All set! Enjoy the movie!
Enter fullscreen mode Exit fullscreen mode

With async/await, the code is more straightforward, resembling the way you would describe the process in real life. The await keyword pauses the execution until the promise is resolved, making the flow of actions easy to follow.

Summary :

  • Callback: A function executed after another function finishes its work.
  • Callback Hell: Nested callbacks leading to hard-to-read code.
  • Promise: A cleaner way to handle asynchronous tasks, avoiding callback hell.
  • Async/Await: A modern, easy-to-read syntax built on promises for handling asynchronous code.

"By mastering callbacks, promises, and async/await, you can turn complex code into a seamless experience. Say goodbye to callback hell and hello to cleaner, more efficient JavaScript. Happy coding!"

Top comments (0)