More ES6 magic: Async/Await
ABailey92
Posted on November 9, 2020
If you thought promises
were the best thing since sliced bread after dealing with callback hell, wait until you discover the JS magic of async
and await
. It's important to note that you must have a general understanding of how promises work in order to truly understand how to use async and await, since they are just syntactical sugar. So I'll start with giving a brief overview
of promises to get you up to speed if you've never heard of them, or give you a refresher if you already know what they are.
Promises Explained
In the words of MDN
A promise is an object which can be returned synchronously from an asynchronous function.
A Promise constructor takes in a function that takes in two parameters: Reject
and Resolve
. It will be in one of 3 possible states:
- Resolved: A Promise was successful in retrieving data or getting a value
- Rejected: A Promise could not retrieve data due to an error or issue
- Pending: not yet Resolved or rejected
A .then
is then chained to run a function upon success and a .catch
is added to provide error handling.
fetch(url)
.then(process)
.then(save)
.catch(handleErrors)
A promise is settled if it’s not pending (it has been resolved or rejected).
How does it get any better than that?
Two words: Async & Await. Well, that's actually three, but I digress.
Let's start with async
. The async keyword can be placed before a function like async function test()
or const test = async() =>{}
. Using the word async before a function means that that function will return a promise. The values returned from that function are automatically wrapped in a resolved promise.
Now onto await
! Await can only be used inside of an async function. You can use async without await but you cannot use await without async. Got it? Good. Await tells javascript to wait, to stop what its doing until the promise returned from the async function is rejected or resolved. Let's take a look at difference.
const noAwait = async() =>{
const {data} = axios.get(url)
console.log(data) // undefined
}
This results in undefined being logged to the console. But why? This is because getting requests take time. As you know javascript is synchronus, so it will continue to move along before that promise is resolved and data is provided a value.
const withAwait = async()=>{
const {data} = await axios.get(url)
console.log(data) // json object
}
This results in json being logged to the console. This is because the await
keyword has been added and tells javascript to wait for the promise to be resolved before it moves on.
You may be thinking: how does error handling work with this syntax? It's very common to use a try and catch
block for error handling with async and await.
async function f() {
try {
let {data} = await axios('http://no-such-url');
} catch(err) {
alert(err); // TypeError: failed to fetch
}
}
f();
Since async function do return promises you can also just chain a .catch
and that will handle a rejected promise as well.
So rather than using promise chaining or the dreaded callback hell nesting, try using async & and await. Together they provide a great framework to write asynchronus code that is easy to read and write.
Posted on November 9, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.