Javascript 等待forEach完成,然后从我的承诺/职能部门返回

Javascript 等待forEach完成,然后从我的承诺/职能部门返回,javascript,node.js,firebase,google-cloud-firestore,Javascript,Node.js,Firebase,Google Cloud Firestore,我使用的是Firebase Cloud Firestore,但是,我认为这可能更像是JavaScript异步与同步承诺返回的问题 我执行一个查询以从一个集合中获取ID,然后循环该查询的结果以基于该ID查找另一个集合中的各个记录 然后我想将找到的每条记录存储到一个数组中,然后返回整个数组 results.length始终为0,因为returnresults在forEach完成之前激发。如果我从forEach内部打印results.length,它就有数据 在从外部承诺和外部功能本身返回之前,我怎么

我使用的是Firebase Cloud Firestore,但是,我认为这可能更像是JavaScript异步与同步承诺返回的问题

我执行一个查询以从一个集合中获取ID,然后循环该查询的结果以基于该ID查找另一个集合中的各个记录

然后我想将找到的每条记录存储到一个数组中,然后返回整个数组

results.length
始终为0,因为
returnresults
在forEach完成之前激发。如果我从forEach内部打印
results.length
,它就有数据

在从外部承诺和外部功能本身返回之前,我怎么能等到forEach完成呢

         getFacultyFavoritesFirebase() {
            var dbRef = db.collection("users").doc(global.user_id).collection("favorites");
            var dbQuery = dbRef.where("type", "==", "faculty");
            var dbPromise = dbQuery.get();
            var results = [];
            return dbPromise.then(function(querySnapshot) {
                querySnapshot.forEach(function(doc) {
                  var docRef = db.collection("faculty").doc(doc.id);
                  docRef.get().then(function(doc) {
                    if (doc.exists) {
                        results.push(doc);
                    }
                  })
                });
                console.log(results.length);
                return results;
            })
            .catch(function(error) {
                console.log("Error getting documents: ", error);
            });
          }

如果循环中同时有多个工作项要执行,则可以收集所有工作项中的所有承诺,并等待它们全部完成。可能解决方案的一般形式如下所示:

const promises = []  // collect all promises here
items.forEach(item => {
    const promise = item.doWork()
    promises.push(promise)
})
Promise.all(promises).then(results => {
    // continue processing here
    // results[0] is the result of the first promise in the promises array
})

您可以根据自己的特定形式对其进行调整。

这里的技巧是用承诺而不是结果填充
结果。然后,您可以对该承诺数组调用
Promise.all()
,并获得所需的结果。当然,在推送承诺之前,您不能检查
doc.是否存在,因此您需要在
promise.all()解决后处理该问题。例如:

function getFacultyFavoritesFirebase() {
    var dbRef = db.collection("users").doc(global.user_id).collection("favorites");
    var dbQuery = dbRef.where("type", "==", "faculty");
    var dbPromise = dbQuery.get();
    // return the main promise
    return dbPromise.then(function(querySnapshot) {
        var results = [];
        querySnapshot.forEach(function(doc) {
            var docRef = db.collection("faculty").doc(doc.id);
            // push promise from get into results
            results.push(docRef.get())
        });
        // dbPromise.then() resolves to  a single promise that resolves 
        // once all results have resolved
        return Promise.all(results)
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });
}

getFacultyFavoritesFirebase
.then(results => {
    // use results array here and check for .exists
}

您可以使用
Promise.all
将一系列承诺合并为一个承诺。我看到一个类似的问题()使用了async/await-在这种情况下正确的语法是:return-await-Promise.all(results)?@Bruce尝试了这个方法,但在我的情况下,用户数据仍然是一个承诺。我尝试了许多类似的解决方案,这是一个有效的方法。谢谢