5 Reasons Why JavaScript Async/Await Over Promises
Mrityunjaya Prajapati
Posted on May 9, 2021
NodeJS supports async/await out of the box since version 7.6. I believe this is one of greatest addition to JS since 2017. If you haven’t tried it yet, here are 5 main reasons reasons with examples why you should adopt it immediately and never look back.
What is Async/Await
Async/await is a new way to write asynchronous code. Previous alternatives for asynchronous code are callbacks and promises. Async/await is actually just syntax built on top of promises. It cannot be used with plain callbacks or node callbacks.
Syntax for Async/Await and Promises
const makeRequest = () =>
getJSON()
.then(data => {
console.log(data)
return "done"
})
makeRequest()
And this is how it looks with async/await:
const makeRequest = async () => {
console.log(await getJSON())
return "done"
}
makeRequest()
Why Is It better?
1. Clean Code
If you compare above code then async/await code is much cleaner compare to promises
2. Error Handling
Async/await makes it finally possible to handle both synchronous and asynchronous errors with the same construct, good old try/catch
const makeRequest = () => {
try {
getJSON()
.then(result => {
// this parse may fail
const data = JSON.parse(result)
console.log(data)
})
} catch (err) {
console.log(err)
}
Now look at the same code with async/await.
const makeRequest = async () => {
try {
const data = JSON.parse(await getJSON())
console.log(data)
} catch (err) {
console.log(err)
}
}
3. Return Conditional Data
const makeRequest = () => {
return getJSON()
.then(data => {
if (data.needsAnotherRequest) {
return makeAnotherRequest(data)
.then(moreData => {
console.log(moreData)
return moreData
})
} else {
console.log(data)
return data
}
})
}
Above example is so messy and nested syntax are really tough to understand.
Look at the same code with async/await.
const makeRequest = async () => {
const data = await getJSON()
if (data.needsAnotherRequest) {
const moreData = await makeAnotherRequest(data);
console.log(moreData)
return moreData
} else {
console.log(data)
return data
}
}
4. Intermediate values
You might have a situation where you call a promise1
and then use what it returns to call promise2
, then use the results of both promises to call a promise3
. Your code most likely looked like this
const makeRequest = () => {
return promise1()
.then(value1 => {
// do something
return promise2(value1)
.then(value2 => {
// do something
return promise3(value1, value2)
})
})
}
This same logic becomes very simple with async/await.
const makeRequest = async () => {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
}
5. Debugging
A killer advantage when using async/await is that it’s much easier to debug. Debugging promises has always been such a pain because of 2 main reasons:
1). You can’t set breakpoints in arrow functions that return expressions.
2). If you set a breakpoint inside a .then block and use debug shortcuts like step-over, debugger will not move to the the following .then because it only steps through synchronous code
const makeRequest = () => {
return callAPromise()
.then(() => callAPromise())
.then(() => callAPromise())
}
With async/await you don’t need arrow functions as much, so you can step through await calls exactly like normal synchronous calls.
const makeRequest = async() => {
await callAPromise()
await callAPromise()
}
Posted on May 9, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.