Snippets for success with Async Await

Atishay Jain
Mar 14, 2019 · 4 min read
Image for post
Image for post

The async-await feature in modern JavaScript is very powerful and can provide a lot of functionality with very little code. The more we get into using async-await, the more we realize that it is not just syntactic sugar, it is a way of thinking. The more we use async await, the more we feel liberated and empowered. Here are some of the snippets in the order of increasing develop power and productivity and not necessarily the increase in code size.

1. Waterfall execution

Waterfall execution of async-await involves just adding await anywhere in the code.

In cases like loops and callbacks, tracking function calls in callbacks is difficult and there are significant benefits of going to async.

Caveat array.forEach cannot have await. Since it returns nothing, we cannot wait for anything. In modern JS, there is little reason to use array.forEach. A for..of loop is better in almost all cases where foreach has been used earlier.

2. Fire and forget

Is is not necesary to use await with async. We can just call and async method and not use await. This way the method would complete when it wants.

Note that this will also ignore all errors. A better implementation would be to write.

3. Catching one of errors

You can use .catch to catch one of errors in the asynchronous code.

You can also rethrow errors.

You can do cleanup using .finally

4. Delayed await

The objective here is to do something in parallel to the synchronous call. This is a very common pattern in network requests. Since they take a lot of time, it is a good idea to trigger them as soon as possible and then do additional tasks like rendering the UI after the network request has been sent. If the response comes early, it can wait but in most cases, it won’t be ready early. But we will be able to save some extra time that was taken by additional code (like crunching the UI together) by sending over the requests early.

5. Parallel functions

Waiting for multiple asynchronous functions running in parallel can be achieved by waiting on Promise.all. Very useful if we have multiple requests on the server that are independent but we need to wait for all of them. We can combine this with method #4 above.

Note that this will not wait for all requests in case some request gives an error. For that we need Promise.allSettled currently on track for standardization in JavaScript.

6. Async function for each array value

Another common pattern is to have asynchronous processing of some data coming from an array. If we need to perform that one by one a for..of look is the solution. But if we want to run that in parallel the following code can be used.

7. Racing asynchronous functions

It is difficult to appreciate exiting when the first of the two asynchronous methods completes. It feels wasteful to run two competing calls. But there are valid use cases for racing asynchronous functions. One of the best use cases is to have a timeout. We could race a method against set timeout and it will provide a one time timeout.

The first line is wrapper over setTimeout to make this async-await compatible. In the next line we race fetch and timeout. The one that completes first returns. If fetch returns first we get the response object. If fetch fails, it would reject immediately and we can catch the error in a try...catch or a .catch(() => ...) block. If fetch succeeds under 2 seconds, its return value is present, otherwise timeout would win the race which would resolve to undefined. We could change this to an error or reject it in case of the timeout.

8. Memoization and solving parallel calls

In most cases when we call the server, we would like to use the value at multiple places but would not want to call the server multiple times. Traditionally this ahs been solved by keeping this output value in a variable (most likely in a store like mobx or redux) and calling a method once to fetch it. Such an approach is needlessly verbose and it prevents us from making the components independent as they depend on someone else to do server fetch. One solution to this is to use memoization — caching the return value from the function if it is called with the same parameterd. The challenge here is that the async functions can take a long time while the download is in progress, there is no data to cache. This problem is not there in async methods as we can cache and reuse promises easily.

This method will only call the server once for any get call and all callers will get the response as quickly as possible. We are using an off the shelf memoize from lodash in this case and ECMA decorators making the code fun to read.

We can also create decorator wrappers for method like console.time, the scope of which discussion is beyond this post.

Hope you find these useful and are able to use these in everyday life.


Originally published at atishay.me on March 14, 2019.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store