Working with promises has become more comfortable since the introduction of async/await and in my opinion it makes code more readable.
By adding async
to a function, it automatically wraps the function in a promise, regardless of its return value. This means async
functions will always return a promise.
const greet = async (name) => {
return `Hey, ${name}!`
}
greet('Ben').then(msg => console.log(msg)) // Hey, Ben!
Now greet
above doesn't really need to run asynchronously but what if we needed to first fetch
the user or perform some long-running task? Enter the await
keyword!
const greet = async (id) => {
let response = await fetch(`user-api/${id}`)
let user = await response.json()
return `Hey, ${user.name}!`
}
greet(7).then(msg => console.log(msg)) // Hey, Ben!
By introducing the await
keyword, the code pauses until the promise settles and its value becomes available. No more nesting .then
methods off the fetch
which makes it arguably easier to follow! It should be noted that one cannot use the await
keyword outside of an async
function – it is a reserved keyword and will result in a syntax error.
Before and After
To help cement the concept that async/await is more readable than chaining .then
methods, let's do a little comparison:
Before
const greet = (id) => {
return fetch(`user-api/${id}`)
.then(response => {
return response.json()
})
.then(user => {
return `Hey, ${user.name}!`
})
}
console.log(greet(7)) // Hey, Ben!
After
const greet = async (id) => {
let response = await fetch(`user-api/${id}`)
let user = await response.json()
return `Hey, ${user.name}!`
}
greet(7).then(msg => console.log(msg)) // Hey, Ben!
Not only does it reduce the code by 3 fewer lines, it also remove complexity – imagine the scenario when you need to make asynchronous calls within one of the .then
callbacks! It just gets to be a nested-callback hell. I consider async/await to be a huge improvement to readability and its a practice that I use quite often.