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!")
}
}
}
}
}
}
}
}
}
}
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")
}
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)
}
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 (2)
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
That's not true. Await will wait for the promise to be resolved or rejected before moving to the next line. Consider the following example:
It will produce:
Whether you use
response
or not, it will go line by line.I trust that this explanation has been helpful. If you have any further questions, please don't hesitate to ask.
Best regards!