Using .map in Promise.all

Viewed 275

So, I have a few promises I need to run on init in my Express Server.

const dates = [];
for (var i = 0; i <= 8; i++) {
  dates.push(
    moment()
      .add(i, "days")
      .format("YYYY-MM-DD")
  );
}
const [cityName, weatherData, celestialData] = await Promise.all([
  axios.get(
    `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${myKey}`
  ),
  axios.get(
    `https://api.darksky.net/forecast/${myKey}/${latitude},${longitude}`
  ),
  dates.map(date => {
    axios.get(
      `https://api.ipgeolocation.io/astronomy?apiKey=${myKey}&lat=${latitude}&long=${longitude}&date=${date}`
    );
  })
]);

I need data from 8 different days so I thought by running a .map with the dates array I would get back another array with the resolved promise from each. This is not working as I expected. How do I manage looped axios calls inside Promise.all?

1 Answers

You're really close. You want to

  1. Spread out the array from dates.map
  2. Capture the results in a rest element in your destructuring
  3. Return the result from axios from the map callback

Roughly:

const [cityName, weatherData, ...celestialData] = await Promise.all([
// 2 −−−−−−−−−−−−−−−−−−−−−−−−−^^^
  axios.get(
    `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${myKey}`
  ),
  axios.get(
    `https://api.darksky.net/forecast/${myKey}/${latitude},${longitude}`
  ),
  ...dates.map(date => {
//^^^−−−− 1
    return axios.get(
//−−^^^^^^ 3
      `https://api.ipgeolocation.io/astronomy?apiKey=${myKey}&lat=${latitude}&long=${longitude}&date=${date}`
    );
  })
]);

celestialData will be an array of the results for the dates.

If you like, you can use a concise arrow function for that third part:

  ...dates.map(date => axios.get(
    `https://api.ipgeolocation.io/astronomy?apiKey=${myKey}&lat=${latitude}&long=${longitude}&date=${date}`
  )

Side note: Your current way of creating the dates array is just fine, but if you wanted, you could use Array.from's mapping ability:

const dates = Array.from(
  Array(9),
  (_, i) => moment().add(i, "days").format("YYYY-MM-DD")
);

Since Seblor hasn't posted it as an answer, here's their approach (which seems better to me since it avoids spreading out an array just to gather it back up again with a rest element in the destructuring):

const [cityName, weatherData, celestialData] = await Promise.all([
  axios.get(
    `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${myKey}`
  ),
  axios.get(
    `https://api.darksky.net/forecast/${myKey}/${latitude},${longitude}`
  ),
  Promise.all(dates.map(date => {
    return axios.get(
      `https://api.ipgeolocation.io/astronomy?apiKey=${myKey}&lat=${latitude}&long=${longitude}&date=${date}`
    );
  }))
]);
Related