A photograph of the author, Alex Kharouk

Alex Kharouk

Asynchronous JavaScript: Await the Signal!

It's starting to make sense. We have the tools in our disposal to not only execute code on the fly, but to keep it in the background if need be. That's quite handy. Only issue is that maybe, we want more with our promises, and less of adding .then()s to our code. We still want promises, but we want them elegantly. Okay, I'll get on with it.

## Thanks for awaiting.

Async & Await were introduced in ES8. They are a little different from the thenning and chaining we have been using, but under the hood it works the same. Syntactic sugar, to help us devs keep "the flow of the code". Instead of .then()s, we use awaits, and we don't chain.

utils/async.ts
// For simplicity's sake, headToShop logs the shop
// From chaining:
headToShop('groceries', car)
.then(() => headToShop('clothes', run))
.then(() => headToShop('shoes', ski))
.then(() => headToShop('accessories', walk))
.then(() => console.log('Done shopping for the day!'))
// To await:
async function beginShopping() {
await headToShop('groceries', car)
// everything waits until 1st promise resolves
await headToShop('clothes', run) // waits..
await headToShop('accessories', walk) // waits..
console.log('Done shopping for the day!')
// ^ prints regardless if the promises have resolved
}
// When we call the async function...
beginShopping()
// we get:
$ car
$ run
$ walk
$ Done shopping for the day!

Key things to point out is that we can only await within an async function. Code (like the console.log) that appears after an await, will execute regardless.

You can store the resolved value in a variable without using a .then(), as well as using it with fetch1.

const success = await headToShop('groceries', car)
// or
const fetchData = async () => {
const response = await fetch('<url>')
const data = await response.json()
console.log({ data })
}

We've talked about Promise.all() in the last post, and we can also use it with async/await.

utils/posts.ts
const posts = Promise.all(getAllPosts()).then((posts) => posts)
// becomes:
const [firstPost, secondPost, thirdPost] = await Promise.all(getAllPosts())

It's a nice improvement, but we must still wrap our awaits in an async function. Currently, there is work being down to allow top-level awaits2, which means that we won't need to have async functions. Currently, Node is experimenting with it, and I'm sure the browsers are too.

awaitChrome.png

Now you might be wondering how do we catch an error that could occur whilst we are awaiting? That's where we use the good ol' fashioned try/catch!

try {
const posts = await Promise.all(getAllPosts())
} catch (error) {
console.error(error)
}

Another way of awaiting an array of Promises is using a new ES9 syntax called async iterators, where we can use a for await of loop to iterate over the array.

const allPosts = posts.map((post) => fetch(post.url))
const asyncLoop = async function () {
// adds the await keyword after the `for`
for await (const post of allPosts) {
const data = await post.json()
}
}

So now you could also iteratively go through each each promise, and await them. Potentially you want the response of a specific promise, and do further data manipulation on that specific promise. However, as it's sequential, you won't have access to the data of later promises in the array. If you have promises the depend on one another, it's best to use Promise.all() to await them all at once.

There is also the Promise.allSettled() method3, which continues to resolve or reject even if a promise has failed to resolve. It's also useful if the promises are independant. Here's an example from the MDN docs that's worth understanding:

const promise1 = Promise.resolve(3)
const promise2 = new Promise((resolve, reject) =>
setTimeout(reject, 100, 'err')
)
const promises = [promise1, promise2]
Promise.allSettled(promises).then((results) =>
results.forEach((result) => console.log(result.status))
)
// expected output:
// "fulfilled"
// "rejected"

### Summary

That was an introduction to the async/await keywords. But there's always more things to pay attention to in JavaScript. Remember how we discussed the language's single thread? Let's dive deeper into that topic on tomorrow's post!