Introduction
async/await
was introduced to solve an issue that Promises
was trying to move away from, the callback hell.
With Promises, chaining several .then(cb)
s makes the code hard to read/follow.
async/await
solves this issue by doing away with .then(cb)
as we shall see.
async/await
does not replace promises but changes how we ‘consume’ Promises.
async/await
is built on Promises
and Generators
and was introduced in ES2017
as a new spec.
Doing async/await
correctly
It’s easy to mix async/await
with the .then(cb)
syntax that Promises
had to offer in ES6
:
async/await
and Promises
are inter-operable. With async/await
offering a better way of consuming Promises
Promises in summary
Promises represent proxy values that will be available in the future depending on whether the Promise
fulfills
with a value or is rejected
with an error
A promise can be in any of one of these states:
pending
state - Initial state, operation not fulfilled/rejectedfulfilled
state - operation completely successfullyrejected
state- operation failed
Image credits MDN
Example in code:
// creating a promise
const fetchFakeUser = () => {
return new Promise((resolve, reject) => {
// simulate a delay e.g when fetching data over HTTP
setTimeout(() => {
resolve({user: 'Itachi Uchiha', token: 'e66d515e-6cbe-46d0-9f22-8705a17b5b6d'})
}, 5000) // delay for 5 seconds
})
}
// consuming the promise
fetchFakeUser()
.then(data => {
// use the data(value) resolved in the promise
console.log(data) // {user: 'Itachi Uchiha', token: 'e66d515e-6cbe-46d0-9f22-8705a17b5b6d'}
})
Promises can be chained: multiple .then()
s can be chained on the promise
const myPromise = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10)
}, 2000)
})
}
myPromise()
.then(val => {return val + 1}) // 11
.then(val => {return val + 1}) //12
.catch(err => console.log(err))
.catch(cb)
handles any error from promise rejection.
How async/await
changes how we consume Promises
Async await does away with the .then()
and employs async
and await
when consuming a Promise.
The above becomes:
const main = async () => {
try {
const val = await myPromise()
return val
} catch(err) {
// handle error from promise rejection here
}
}
We make our function async
and append await
to myPromise()
call then use the returned value as one would in a regular function.
Where the mix up comes in:
Mixing async/await
and .then
For example:(from the snippet above:) it’s tempting to do:
const user = await fetchFakeUser().then(user => {
if(user) return user
// preceding lines of code
}).catch(err => {
// do something
})
summary
async/await
does away with the need to use .then(cb)
and .catch(cb)
when consuming promises. All we need is to:
- Append
async
to the function that will be consuming a promise to useawait
- Wrap call to the function that returns a
Promise
inside atry...catch(e) {}
block - Store the value return from the function in a variable and prepend
await
to the function returning a promise.
Note: Always remember to prepend await
to a function call that returns a promise