【问题标题】:Firebase asyc/await not returning complete result from foreach loopFirebase async/await 未从 foreach 循环返回完整结果
【发布时间】:2021-12-08 21:56:19
【问题描述】:

我正在努力让它正常工作。我的 nodejs 后端有这个功能

let data = [];
let lists = [];
var userId = request.params.userId;
var coll = db.collection("forms");
var query = coll.where("formUser", "==", userId);
await query.get().then(function (querySnapshot) {
    querySnapshot.forEach(function (doc) {
        var forms = doc.data();
        var listIDs = doc.data().formLists;

        listIDs.forEach(listId => {
            db.collection("lists").where("listId", "==", listId).get().then(function (snapshot) {
                snapshot.forEach(function (d) {
                    lists.push({ "id": d.data().listId, "text": d.data().listName });
                });
            });
        });
        forms.formLists = lists;
        data.push(forms);
    });
});

由于某种原因,第二个循环不只是工作,数据的结果来自第一个循环,如果我将相同的函数放在我的 javascript 前端,我会得到带有 listIDs 结果的完整数据。

有什么想法吗?

【问题讨论】:

  • 虽然this question 处理来自异步调用的 Promise,但它包含大量与您的问题相关的信息。另请查看侧栏中的许多链接问题。
  • @samthecodingman 谢谢,我认为问题不在于基于您共享的链接的返回 ajax,而在于我上面的后端函数。我觉得我必须围绕 Promise.all 做点什么,但不知道怎么做。
  • 这里是another question,为您的问题提供相同的解决方案。

标签: node.js firebase async-await google-cloud-functions


【解决方案1】:

添加单个await 并不会突然让其下的所有代码同步运行。在你做的时候,结合awaitthen 通常也是一种反模式。我建议您在掌握异步行为之前远离async / await,并坚持使用then 并在此之前明确处理承诺。

如果您共享的代码在 Cloud Functions 中运行,则您需要返回一个在所有异步(读取和写入)操作完成后解析的 promise。由于您有很多这样的操作,您需要将从它们获得的所有承诺捕获到一个数组中,然后使用Promise.all() 作为返回值:

var userId = request.params.userId;
var coll = db.collection("forms");
var query = coll.where("formUser", "==", userId);
return query.get().then(function (querySnapshot) { // ?
    let promises = []; // ?
    querySnapshot.forEach(function (doc) {
        var forms = doc.data();
        var listIDs = doc.data().formLists;

        listIDs.forEach(listId => {
            promises.push(db.collection("lists").where("listId", "==", listId).get()); // ?
        });
    });
    return Promise.all(promises).then(function (snapshot) { // ?
        return snapshot.map((d) => {
            return { "id": d.data().listId, "text": d.data().listName };
        });
    });
});

【讨论】:

  • 非常感谢弗兰克,但仍然不确定如何将这些放在一起,我需要在数据结果的每个过程中将数据附加到forms.formLists = lists; data.push(forms);,而您上面的代码让我迷失了var forms现在似乎无法使用。
【解决方案2】:

因此,对于那些在如此复杂的数据结构中苦苦挣扎的人来说,这就是我所做的:

        let data = [];
        let forms = [];
        let lists = [];
        var userId = request.params.userId;
        var coll = db.collection("forms");
        var query = coll.where("formUser", "==", userId);
        await query.get().then(function (querySnapshot) {
            querySnapshot.forEach(function (doc) {
                forms.push(doc.data());
            });
        });

        for (let index = 0; index < forms.length; index++) {
            const element = forms[index];
            var listIDs = element.formLists;
            for (const listId of listIDs) {
                await db.collection("lists").where("listId", "==", listId).get().then(function (snapshot) {
                    snapshot.forEach(function (d) {
                        lists.push({ "id": d.data().listId, "text": d.data().listName });
                    });
                });
            }
            element.formLists = lists;
            data.push(element);
        }
                            
        response.status(200).send(data); // pass your data to UI

【讨论】:

  • 您好,我是否可以建议您接受您自己的答案,以便问题显示为已回答,因此对于那些可能像您所建议的那样在数据结构上苦苦挣扎的人来说更容易看到?
猜你喜欢
  • 2022-10-04
  • 2018-03-03
  • 2017-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
  • 2022-06-23
相关资源
最近更新 更多