Firebase asyc/await 未从 foreach 循环返回完整结果
Firebase asyc/await not returning complete result from foreach loop
我正在努力让它正常工作。我的 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 前端中,我将获得带有 listID 的完整数据结果。
有什么想法吗?
添加单个await
不会突然使它下面的所有代码运行同步。它通常也是一种将 await
和 then
组合在一起的反模式。我建议在您掌握异步行为之前远离 async
/ await
,并在此之前坚持使用 then
并明确处理承诺。
如果您在 Cloud Functions 中共享的代码 运行,您将需要 return 一个承诺,在所有异步(读取和写入)操作完成后解析。因为你有很多这样的操作,你会想把你从他们那里得到的所有承诺捕获到一个数组中,然后使用 Promise.all()
作为 return 值:
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 };
});
});
});
所以对于那些在如此复杂的数据结构中挣扎的人来说,这是我所做的:
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
我正在努力让它正常工作。我的 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 前端中,我将获得带有 listID 的完整数据结果。
有什么想法吗?
添加单个await
不会突然使它下面的所有代码运行同步。它通常也是一种将 await
和 then
组合在一起的反模式。我建议在您掌握异步行为之前远离 async
/ await
,并在此之前坚持使用 then
并明确处理承诺。
如果您在 Cloud Functions 中共享的代码 运行,您将需要 return 一个承诺,在所有异步(读取和写入)操作完成后解析。因为你有很多这样的操作,你会想把你从他们那里得到的所有承诺捕获到一个数组中,然后使用 Promise.all()
作为 return 值:
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 };
});
});
});
所以对于那些在如此复杂的数据结构中挣扎的人来说,这是我所做的:
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