Matt Aft Matt Aft -4 years ago 80
Javascript Question

Await for API response in a loop

I am iterating over an array and making a REST API call for each item, but I'm having trouble with the async nature of js. I am trying to use async/await but I don't think I'm setting it up correctly because it won't wait for the response and returns undefined.

onSearchSuccess = async (response) => {
const persons = response._embedded.persons_search_collection;
const personsWithClasses = await persons.reduce(
(acc, person) => {
const params = {
person_id: person.person_id,
date: '2017-01-05',
enrollment_status: 3,
class_status: 2,
};
return getClasses( //this function does an GET request and returns the response
params,
(classesResponse) => {
const { classes } = classesResponse._embedded;
console.log(classes); //logs after the console.log below
return [...acc, { ...person, classes }];
},
() => acc,
);
}, []);
console.log(personsWithClasses); //return undefined
}


export const getClasses = (params, success, error) => {
axios.get(`${uri}/classes`, { params })
.then(({ data }) => {
success(data);
})
.catch(err => error(err));
};

Answer Source

As I mentioned in the comments, reduce won't work as you want if you call async functions. You can use Promise.all and .map as so (I tried to use async/await as much as possible):

onSearchSuccess = async (response) => {
  const persons = response._embedded.persons_search_collection;
  let personsWithClasses = await Promise.all(persons.map(async (person) => {
    try {
      const classes = await getClasses({
        person_id: person.person_id,
        date: '2017-01-05',
        enrollment_status: 3,
        class_status: 2,
      });

      return {...person, classes};
    } catch(error) {
      // ignore errors if a person wasn't found
      return null;
    }
  }));
  personsWithClasses = personsWithClasses.filter(x => x != null);
  console.log(personsWithClasses);
}


export const getClasses = params => {
  return axios.get(`${uri}/classes`, { params });
};

Also note the changes I made to getClasses. There is no reason to have it accept callbacks if axios.get returns a promise anyway.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download