Author avatar

Zachary Bennett

Async/Await Keywords with Array.Map in React

Zachary Bennett

  • Oct 10, 2020
  • 5 Min read
  • 77 Views
  • Oct 10, 2020
  • 5 Min read
  • 77 Views
Web Development
Front End Web Development
Client-side Frameworks
React

Introduction

Asynchronous code is notoriously hard to understand and debug. All sorts of languages have different constructs for helping to manage this complexity. For the longest time, the only way to manage asynchronous code while using JavaScript was to use callbacks. Callbacks are functions that "call back" (execute) when an asynchronous piece of code is done running. The problem with this technique was that it led to badly nested asynchronous code that was really hard to reason about! "Callback hell" was a term coined during this time period.

As JavaScript progressed, promises were added to the language in order to help better reason about asynchronous code and to provide a "then-able" construct for executing long-running operations. However, promises still involved some manner of function nesting and sometimes could be harder to reason about than callbacks (depending upon the problem at hand). The async/await syntax is the solution to this problem. By providing a form of "syntactic sugar" on top of promises, the async and await keywords make asynchronous code look like synchronous code! Using these keywords can help dramatically simplify your code.

In this guide, we will specifically talk about how to use async/await syntax with the Array.map function available to all arrays in JavaScript. You will learn how to easily execute many asynchronous pieces of code in parallel using nothing but pure JavaScript.

Let's get started!

Async/Await Overview

The async/await keywords are a wonderful mechanism for modeling asynchronous control-flow in computer programs. In JavaScript, these keywords are "syntactic sugar" on top of promises—they abstract away any calls you need to make to Promise.then. In the following code, you can see an example of an asynchronous function within a React component:

1
2
3
4
5
6
7
8
...

executeLongRunningTask = async () => {
    const response = await fetch(this.taskUrl);
    return await response.json();
}

...
jsx

The code above fetches some JSON from an API. You can see that the async keyword is used in front of the function declaration. This enables you to use the await keyword to synchronously resolve promises within the function. When you use the await keyword, you are guaranteed that the execution of your function will pause until await finishes resolving your promise.

Now that you have seen and understand how to use async/await syntax, let's see how you can use it with Array.map to compose many long-running tasks.

Using Async Functions With Array.map

Array.map is a function available on the Array prototype hierarchy. This essentially means that any JavaScript array has access to the map function. This function receives a function as an argument and calls the given function for each item in the array, returning a value for each item that is iterated over. What's so powerful about this is that you can use Array.map with an async function in order to generate an array of promises! This means that you can iterate over items in an array and return a promise for each one of these items in a succinct and readable manner. In the below code, you can see the updated function that composes many long-running tasks.

1
2
3
4
5
6
7
8
9
10
11
12
13
...

private taskUrls = [taskOneUrl, taskTwoUrl, taskThreeUrl];

executeLongRunningTask = async (url) => {
    return await fetch(url).then(response => response.json());
}

executeAllLongRunningTasks = async () => {
    return await Promise.all(taskUrls.map(this.executeLongRunningtask);
}

...
jsx

As you can see, in the above code the executeLongRunningTask async function is passed into the map call, which is mapping over a list of task URLs. For each of these URLs, a promise is returned. At the end of this iteration, an array of promises is generated. This enables the use of Promise.all, which attempts to resolve every promise within an array in parallel and have itself resolve when all of the promises within it are complete.

You can now use this executeAllLongRunningTasks function to log your new array of resolved task responses to the console like this:

1
2
3
4
5
...

this.executeAllLongRunningTasks().then(console.log);

...
jsx

Or, if you want to use it within an async function or top-level async module:

1
2
3
4
5
6
...

const tasks = await this.executeAllLongRunningTasks();
console.log(tasks);

...
jsx

Conclusion

The async/await keywords are an extremely powerful means of reasoning about asynchronous code. Using them will make your code more readable and thus more maintainable. When using async/await alongside Array.map, you have a powerful means of executing many asynchronous functions either in sequence or in parallel.

You can now be confident when it comes to composing asynchronous functions using Array.map! For more information, check out the documentation for async/await syntax.

1