DEV Community

Pan Wangperawong
Pan Wangperawong

Posted on • Updated on

Async-Await vs. Then to Avoid Callback Hell 📞😈

Dante's Inferno Callback Hell

Callback Hell 🔥

When working with JavaScript, there is a concept known as callback hell. It describes a deeply nested set of callback functions that is hard to read and maintain. Callback hell happens due to the asynchronous non-blocking nature of JavaScript. Below is an illustration based on Dante's 😈 nine circles of hell.

hell() {
    firstCircle() {
        secondCircle() {
            thirdCircle() {
                fourthCircle() {
                    fifthCircle() {
                        sixthCircle() {
                            seventhCircle() {
                                eighthCircle() {
                                    ninthCircle() {
                                        alert("Hell has Frozen Over!")
                                    }
                                }
                            }
                        }    
                    }
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Promises

You commonly encounter callback hell when making an AJAX HTTP request. To flatten out nested callbacks for readability and maintainability, Promises can be used. With Promises, there are two techniques for flattening out our callbacks -- (1) then and (2) async-await.

then

This pattern helps flatten out nested callbacks into sequential thens. The entire execution of this fetch request is completely asynchronous and non-blocking.

someFunc() {
    fetch('https://someurl.com')
        .then((response) => response.json())
        .then((data) => console.log(data)

    console.log("I will not be blocked")
}
Enter fullscreen mode Exit fullscreen mode

async-await

This pattern does the same thing, but is different because each line with await causes the code execution to block while waiting for the promise to resolve.

async someFunc() {
    let response = await fetch('https://someurl.com'),
           data = await response.json()
    console.log("I will be blocked until I get a response", data)
}
Enter fullscreen mode Exit fullscreen mode

async-await vs then

async-await

Useful to use if your code works with Promises and needs to execute sequentially. Due to blocking, you might lose some ability to process code in parallel. I've primarily used async-await when making API requests from a Node.js server.

then

This has been most useful for me when working on the client so the UI thread is not blocked since requests are being processed in parallel. If you develop your frontend with React.js, a typical use case might be to display a loading screen until a fetch request returns and then using a setState to update the UI.

Conclusion

Both Promise mechanisms can be used to solve the callback hell issue, each with their own optimal use cases. Don't limit yourself to any dogma. Do what makes sense for your use case.

If you found this content useful and would like to get updates on new content, follow me on Twitter @itspanw.

Top comments (1)

Collapse
 
smolinari profile image
Scott Molinari

Correct me if I am wrong, but the console log with async/ await is only blocked, because the data variable is in it. If you had of done the same above with the .then example, that console log would be blocked too.

Or put another way, take out the data variable and the async/ await example won't block either.

Scott