Using Async / Await with the Array Reduce Method

Jordan McRae's profile picture

Jordan McRae

Full Stack Javascript Developer

ยท 3 min read


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.

const fetchJobs = async () => { const locations = [ 'toronto', 'vancouver', 'boston' ]; return await locations.reduce(async (jobsAccumulator, location) => { const jobPostingsCall = await fetch(`https://jobs.github.com/positions.json?description=javascript&location=${location}` ); const jobPostings = await jobPostingsCall.json(); jobsAccumulator.push({ location, jobPostings, }); return jobsAccumulator; }, []); }

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
const fetchJobs = async () => { const locations = [ 'toronto', 'vancouver', 'boston' ]; return await locations.reduce(async (previousPromise, location) => { let jobsArray = await previousPromise; const jobPostingsCall = await fetch(`https://jobs.github.com/positions.json?description=javascript&location=${location}` ); const jobPostings = await jobPostingsCall.json(); jobsArray.push({ location, jobPostings, }); return jobsArray; }, Promise.resolve([])); }

The first change to take a look at above is on line 12. 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.

You can play around with the Code Pen here.


Open Source
Enterprise
Evaluation
Share

Stack Five is a React and NodeJS consulting company that strives to push the boundaries of the web and build meaningful things. If you're looking to create a cutting-edge web application or need software engineering resources for your project, please contact us.

Stack Five logo

2020 Stack Five Inc. | Toronto, Canada