【问题标题】:Returning a promise inside a forEach on node v 6.11.5在节点 v 6.11.5 上的 forEach 中返回一个承诺
【发布时间】:2018-09-03 02:12:38
【问题描述】:

我正在开发在 Node v6.11.5 上运行的 Firebase Cloud Function,因此我无法使用 Async Await(据我所知)。总体思路是,我遍历对象,提取数据,在不同的服务器上 ping 一个返回相关信息的 API,然后将新信息添加到对象,然后再将其添加到数组并继续。

API 返回信息,但不及时。如果我注销该对象,它会返回 3 个字段,但匹配项为空。

这会是我应该使用Promise.all() 的一个实例吗?如果是,如何使用。我尝试将getMatches 创建为一个promise,但该函数会继续运行。

...
const list = [];
...
return db.collection('users').get()
  .then((snapshot) => {
    return snapshot.forEach((doc) => {
      const user = doc.data();
      const obj = {};
      obj.id = user.id;
      obj.name = user.name;
      obj.matches = [];

      try {
        getMatches(user.param1, user.param2)
          .then(res => {
            obj.matches.push(res);
          })
      }
      catch (error) {
        console.log('error => ', error);
      }

      list.push(obj);
    });
  })
  .then(() => {
    ... sorts list ...
  })
  .then(() => {
    ... returns list to database ...
  });

const getMatches = function (param1, param2) {
  const url = 'https://something.herokuapp.com/callback.php';
  return axios.post(url, qs.stringify({
      data: param1,
      name: param2
    }))
    .then(res => {
      return res.data;
    })
    .catch(error => {
      console.log('ERROR => ', error);
    });
}

【问题讨论】:

  • 如果您在 Firebase 项目中使用 TypeScript,则可以使用 async/await。它将转译为 ES6,Cloud Functions 将运行该 ES6。但这仍然无法帮助您处理 foreach 循环中的承诺。

标签: javascript firebase promise es6-promise


【解决方案1】:

是的,在继续之前使用 Promise.all 检查每个 getMatches 是否得到解决(并推送到列表中):

return db.collection('users').get()
  .then((snapshot) => {
    const allPromises = snapshot.map((doc) => {
      const user = doc.data();
      const obj = {};
      obj.id = user.id;
      obj.name = user.name;
      obj.matches = [];
      return getMatches(user.param1, user.param2)
        .then(matchPromise => {
          obj.matches.push(res);
          list.push(obj);
        });
    });
    return Promise.all(allPromises);
  })
  .then(() => {
    ... sorts list ...
  })
  .then(() => {
    ... returns list to database ...
  });

【讨论】:

    【解决方案2】:

    QuerySnapshot 中而不是使用forEach 方法。有一个属性调用 docs 以将结果作为数组获取,然后您可以将 map 放入 Promises 数组中。

    参考:Firebase QuerySnapshot

    db.collection('users').get()
      .then((querySnapshot) => {
        // 1. Get docs by properties `docs`
        const docs = querySnapshot.docs;
        
        // 2. Use map to convert array of doc into array of promise 
        const getMatchesPromises = docs.map(doc => {
          const user = doc.data();
          return getMatches(user.param1, user.param2)
            .then(res => {
              return {
                id: user.id,
                name: user.name,
                matches: [res],
              }
            });
        });
        
        // 3. Call Promise.all to execute array of promises, 
        // return the result so we can catch them in next then.
        return Promise.all(getMatchesPromises);
      })
      .then(list => {
        // ... your desired result from Promise.all
        /*
        list = [
          { id: 1, name: 'AAA', matches: [...] },
          { id: 2, name: 'BBB', matches: [...] },
        ];
        */
      });

    【讨论】:

      猜你喜欢
      • 2018-06-17
      • 2016-12-05
      • 2015-11-27
      • 1970-01-01
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 2019-07-14
      • 2018-10-11
      相关资源
      最近更新 更多