【问题标题】:Use Promise or Await in firebase query在 firebase 查询中使用 Promise 或 Await
【发布时间】:2020-03-03 03:07:03
【问题描述】:

我正在尝试运行一个获取位置集合的查询。然后它需要根据临时集合检查每个位置,以确保它不存在。如果它不存在,它将进入数组。接下来它循环遍历数组并随机抓取三个。

这是我的代码:

let locations = []
        let getLocations = db.collection('locations')
            .where('area', '==', 'central')
            .get().then(snapshot => {
                snapshot.forEach(doc => {
                    let loc = doc.data()
                    loc.id = doc.id

                    console.log('1')

                    let locationsplayedRef = db.collection('locationsplayed')
                    locationsplayedRef = locationsplayedRef.where('location_id', '==', loc.id)
                    locationsplayedRef.get().then(snapshot => {
                        // make sure the location is not already in the db
                        if (snapshot.empty) {
                            // only grab activated locations
                            if(!loc.deactivated)
                                locations.push(loc)                    
                        }

                        console.log('2 ', locations)
                    })

                })

            }).then(() => {
                for (let i = locations.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [locations[i], locations[j]] = [locations[j], locations[i]];
                }

                let third = locations[0];
                let [first, second] = locations.filter(l => !l.restaurant).slice(1);
                let selectedLocations = [first, second, third];

                console.log('3 ', selectedLocations)
            })

当前代码的问题是控制台日志看起来像这样 1 3 2 我需要 1 2 3。我知道我需要使用 promise 或 await,但我还是新手,不知道如何使用实施它。

有人可以告诉我如何使用 Promise 或 Await 以便我的代码以正确的顺序运行吗?

【问题讨论】:

    标签: javascript firebase promise async-await


    【解决方案1】:

    有两个想法会很有用:(1) 分解,这样你就可以看到发生了什么,开发更小的、可测试的函数。 (2)Promise.all(),执行循环中生成的每一个promise。

    // return a promise that resolves to the passed loc or null if the loc is played
    function isLocationPlayed(loc) {
      let locationsplayedRef = db.collection('locationsplayed')
      locationsplayedRef = locationsplayedRef.where('location_id', '==', loc.id)
      return locationsplayedRef.get().then(snapshot => {
        // make sure the location is not already in the db
        return (snapshot.empty && !loc.deactivated) ? loc : null
      })
    }
    
    // return a promise that resolves to an array of locations that have been played
    playedLocations() {
      let locations = []
      let getLocations = db.collection('locations').where('area', '==', 'central')
      return getLocations.get().then(snapshot => {
        // build an array of promises to check isLocationPlayed
        let promises = snapshot.docs.map(doc => {
          let loc = doc.data()
          return isLocationPlayed(loc)
        })
        // resolve when all of the passed promises are resolved
        return Promise.all(promises)
      }).then(results => {
        return results.filter(e => e) // remove nulls
      })
    }
    
    playedLocations().then(locations => {
      console.log(fyShuffle(locations))
    })
    
    // shuffle an array using Fisher Yates
    function fyShuffle(a) {
      for (let i = a.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
      }
      return a;
    }
    

    【讨论】:

      【解决方案2】:

      我无法测试下面的代码,但是你能试试下面的。

      注意asyncawait

        async someFunction() {
          const locations = [];
      
          await db
            .collection("locations")
            .where("area", "==", "central")
            .get()
            .then(async snapshot => {
              const docs = snapshot.docs;
              // Must use for of loop here
              for (const doc of docs) {
                const loc = doc.data();
      
                await db
                  .collection("locationsplayed")
                  .where("location_id", "==", loc.id)
                  .get()
                  .then(snapshot => {
                    // make sure the location is not already in the db
                    if (snapshot.empty) {
                      // only grab activated locations
                      if (!loc.deactivated) {
                        locations.push(loc);
                      }
                    }
                  });
              }
            });
      
          for (let i = locations.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [locations[i], locations[j]] = [locations[j], locations[i]];
          }
      
          let third = locations[0];
          let [first, second] = locations.filter(l => !l.restaurant).slice(1);
          let selectedLocations = [first, second, third];
        }
      

      【讨论】:

      • 谢谢你,菲利普,这是一个很好的解决方案,但我最终选择了更清洁的方法。
      猜你喜欢
      • 2017-09-28
      • 2018-01-03
      • 2020-11-29
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 2019-04-17
      • 2017-05-07
      • 2021-07-11
      相关资源
      最近更新 更多