【问题标题】:How do I return a pushed array after awaiting for async .map() to finish?等待 async .map() 完成后如何返回推送的数组?
【发布时间】:2020-01-11 18:39:42
【问题描述】:

最终结果打算存储在下面的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)

我希望这个问题不会让人觉得很愚蠢。此外,任何关于编写代码错误的反馈或指示都将不胜感激!

【问题讨论】:

    标签: javascript promise async-await axios


    【解决方案1】:

    使用 async/await,您不必使用像 .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 将在任何请求失败后立即停止。因此,您可以在Promise.all 映射中的每个 axios 调用中添加一个.catch,以防止整个批次被拒绝。然后,您将获得一个与位置结果数量匹配的数组,您现在将是失败的数组,因为它们将是 null,或者您想要为失败的请求返回的任何内容。

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

    【讨论】:

    • 解决这个问题的方法非常清晰,感谢您指出不同的方法!
    • 很高兴能帮上忙!
    猜你喜欢
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-22
    • 2016-09-10
    • 2021-11-13
    相关资源
    最近更新 更多