Using Async / Await with the Array Reduce Method

Jordan McRae

Co-founder

2 min

Article Banner

Overview

If you've ever tried using async / await inside of Array.reduce(), you've likely stumbled into errors such as array.push() is not a function, or cannot read .push() of undefined. Fear not! We will walk through a simple example to get you on your way.

Example

Let's use an example where we want to create a function that fetches JavaScript job postings from three cities: Toronto, Vancouver and Boston.

1const fetchJobs = async () => {
2  const locations = [ 'toronto', 'vancouver', 'boston' ];
3
4  return await locations.reduce(async (jobsAccumulator, location) => {
5    const jobPostingsCall = await fetch(`https://jobs.github.com/positions.json?description=javascript&location=${location}` );
6
7    const jobPostings = await jobPostingsCall.json();
8
9    jobsAccumulator.push({
10      location,
11      jobPostings,
12    });
13
14    return jobsAccumulator;
15  }, []);
16}

In the above example, our function will loop through each of the three locations, make an API call for job posting data, and add the data and location to an array. If you were to run this function, you'd receive the error jobsAccumulator.push is not a function. Why is that? The culprit is with our accumulator. If you add a console.log() message at the top of the reducer, you'll see during the second iteration that jobsAccumulator is an unresolved promise.

To fix this, we need to do two things:

  1. Set our initial accumulator (source array) as a promise resolution
  2. Wait on our job posting data to load in each iteration before continuing on to the next
1const fetchJobs = async () => {
2  const locations = [ 'toronto', 'vancouver', 'boston' ];
3
4  return await locations.reduce(async (previousPromise, location) => {
5    let jobsArray = await previousPromise;
6
7    const jobPostingsCall = await fetch(`https://jobs.github.com/positions.json?description=javascript&location=${location}` );
8
9    const jobPostings = await jobPostingsCall.json();
10
11    jobsArray.push({
12      location,
13      jobPostings,
14    });
15
16    return jobsArray;
17  }, Promise.resolve([]));
18}

The first change to take a look at above is on line 17. We're setting our accumulator as a resolved promise that contains an array. We're doing this so that we can resolve our previous promises before continuing on to the next.

The other key piece is on line 5. We've renamed our accumulator to previousPromise so that we can get a better idea of what's happening behind the scenes. Before continuing through each iteration, we're waiting on the previous promise to resolve and then we fetch the next set of job postings.

And it's as simple as that! After the reduce method has finished, our function fetchJobs() should return a nicely formatted array of job postings for each location.