等待异步.map()完成后如何返回推送的数组?

时间:2019-09-10 02:57:41

标签: javascript promise async-await axios

最终结果应存储在下面的locations数组中。

const locations = []

我创建了一个异步函数,该函数接受一个location参数,然后locationSearch将使用该参数向Google Places发出GET请求。

const locationSearch = await (
    axios.get(`https://maps.googleapis.com/maps/api/place/textsearch/json?query=${location}`, {json: true})
    .then(response => {
        if(response.data.results.length < 1) throw new Error('Unable to find location.')

        return response.data.results
    }).catch(error => {
        return error
    }) 
)

结果返回一个位置数组,然后我将使用locationSearch传递到place_id以获取更多详细信息。

const locationDetails = await locationSearch.map(async (locationData) => {
    const { place_id: id } = locationData

    await (
        axios.get(`https://maps.googleapis.com/maps/api/place/details/json?placeid=${id}`, {json: true})
        .then(locationDetails => {
            if(locationDetails.data.result.length === 0) throw new Error('Unable to find location ID!')

            const { name, geometry, types, photos, rating, user_ratings_total, opening_hours, icon, formatted_address, formatted_phone_number, price_level, reviews } = locationDetails.data.result
            locations.push({
                latitude: geometry.location.lat,
                longitude: geometry.location.lng,
                types,
                reviews,
                photos,
                rating,
                user_ratings_total, 
                opening_hours,
                icon,
                name,
                location: formatted_address,
                formatted_phone_number,
                price_level
            })
        }).catch(error => {
            return error
        })
    )
})

但是,我不确定应该返回哪里,因为locationDetails仅用于将结果映射到locations中。已解决的Promise返回如下:

return Promise.all(locationSearch, locationDetails)

我希望这个问题不会这么愚蠢。此外,对于所编写代码的错误有任何反馈或指点,我们将不胜感激!

1 个答案:

答案 0 :(得分:1)

使用异步/等待,您无需使用诸如.then.catch之类的Promise API,这是使用Promise结构的替代方法。它应该看起来像这样:

async function getLocationData (location) {
  try {
    const { data } = axios.get(
      `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${location}`,
      { json: true }
    )

    if (data.results) {
      const locationDetails = await Promise.all(
        data.results.map(({ place_id }) =>
          // for each of these, catch any errors and return null so you know you got nothing
          // but it won't kill the entire batch of requests
          axios.get(
            `https://maps.googleapis.com/maps/api/place/details/json?placeid=${id}`,
            { json: true }
          ).catch(() => null)
        )
      )
      return locationDetails.reduce((arr, details) => {
        // only add the data if it exists
        if (Array.isArray(details.result) && details.result.length) {
          const {
            name,
            geometry,
            types,
            photos,
            rating,
            user_ratings_total,
            opening_hours,
            icon,
            formatted_address,
            formatted_phone_number,
            price_level,
            reviews
          } = details

          return [
            ...arr,
            {
              latitude: geometry.location.lat,
              longitude: geometry.location.lng,
              types,
              reviews,
              photos,
              rating,
              user_ratings_total,
              opening_hours,
              icon,
              name,
              location: formatted_address,
              formatted_phone_number,
              price_level
            }
          ]
        }
        // otherwise it's an errored result (null) or no match
        // so return the accumulated array (essentially a filter)
        return arr
      }, [])
    } else {
      throw new Error('Unable to find location')
    }
  } catch (err) {
    return err
  }
}

这里要注意的主要事情是,Promise.all将在任何请求失败后立即停止。因此,您可以向.catch映射中的每个axios调用添加Promise.all,以防止整个批次被拒绝。然后,您将得到一个与定位结果数量匹配的数组,并且现在将得到失败的数组,因为它们将是null,或者您想为失败的请求返回的内容。

此外,保持一致的错误处理方式也是一个好主意。要么一直扔,要么一直返回。