【发布时间】:2019-05-10 23:17:05
【问题描述】:
我正在将此代码从实时数据库转换为 Firestore。
为了创建一些稍后处理的作业,代码循环通过 Firestore 中的每个用户 (doc),然后通过每个用户内的 2 个嵌套子集合的每个文档。
我希望函数在完成之前等待每个查询完成。 Promise.all() 总是在添加 3 个 Promise 后触发,其中第一个未定义。
我尝试过使用 async/await,但这不是目标。 我尝试为最嵌套的逻辑(writeJobToBackLog())创建一个单独的 Promise 数组。 两者都没有成功。
玩了几个小时后,我什至不明白发生了什么,我的日志记录技能可能使我无法获得更清晰的画面。
我不是 Promise 的专家,但我已经完成了一些工作,主要是使用实时数据库。
var database = admin.firestore();
// prepare()
test();
function test() {
console.log("prepare() called ...");
let promises = [];
database
.collection("users")
.get()
.then((snapshot) => {
snapshot.forEach((user) => {
user = user.data();
const userId = user.userId;
database
.collection("users")
.doc(userId)
.collection("projects")
.get()
.then((snapshot) => {
snapshot.forEach((project) => {
project = project.data();
const projectUrl = project.projectUrl;
const projectId = project.projectId;
database
.collection("users")
.doc(userId)
.collection("projects")
.doc(projectId)
.collection("subProjects")
.get()
.then((snapshot) => {
snapshot.forEach((subProject) => {
subProject.keywords.map(async (keyword) => {
let unreadyJob = {
keyword: keyword,
};
// returns a promise
let write = writeJobsToBackLog(unreadyJob);
writePromises.push(write);
return null;
});
return;
});
return;
})
.catch((error) => {
console.log(error);
})
return;
});
return;
})
.catch((error) => {
console.log(error);
})
});
return;
})
.catch((error) => {
console.log(error);
})
Promise.all(promises)
.then(() => {
console.log("prepare() finished successfully..." +
promises.map((promise) => {
console.log(promise);
return null;
}));
return null;
})
.catch((error) => {
console.log("prepare() finished with error: " + error + "...");
return null;
});
}
function writeJobsToBackLog(unreadyJob) {
console.log("writing job to Backlog ...");
return database
.collection("backLog")
.doc()
.set(unreadyJob);
}
这是打印到控制台的内容:
prepare() called ...
prepare() finished successfully...
writing job to Backlog ...
writing job to Backlog ...
writing job to Backlog ...
writing job to Backlog ...
(... more of those ...)
一切都按预期工作,但 Promise.all 逻辑。 我希望它为每个“写入”使用一个返回的承诺填充承诺数组,然后等待所有写入成功。
根本没有向数组添加任何承诺。
感谢您的帮助!
所以我改了代码:
async function test() {
console.log("prepare() called ...");
const users = await database.collection("users").get();
users.forEach(async (user) => {
const userId = user.data().userId;
const projects = await database
.collection("users")
.doc(userId)
.collection("projects")
.get();
projects.forEach(async (project) => {
const projectUrl = project.data().projectUrl;
const projectId = project.data().projectId;
const subProjects = await database
.collection("users")
.doc(userId)
.collection("projects")
.doc(projectId)
.collection("subProjects")
.get();
subProjects.forEach(async (subProject) => {
subProject.data().keywords.map(async (keyword) => {
let unreadyJob = {
keyword: keyword,
};
await writeJobsToBackLog(unreadyJob);
});
});
});
});
console.log("finished");
}
function writeJobsToBackLog(unreadyJob) {
console.log("writing job to Backlog ...");
return database
.collection("backLog")
.doc()
.set(unreadyJob);
}
它产生相同的结果:
prepare() called ...
finished
writing job to Backlog ...
writing job to Backlog ...
writing job to Backlog ...
...
我做错了什么。谢谢!
【问题讨论】:
-
这是一种非常糟糕的使用 Promise 的方式。使用 Promise 链接而不是嵌套。
-
感谢您的回答。你能举个例子吗?如果没有“promises.push()”,它们会被链接起来,不是吗?
-
即使在删除
promise.push()之后,您也已经嵌套了 firestore 返回的承诺。查看Chaining Promises 和this -
Promise.all不是用来表示相互独立的promise吗? -
谢谢。我如何避免与“forEach”嵌套?我真的不知所措......这对逻辑有何影响?代码可能更扁平/更干净,但仍然在做同样的事情?感谢您的帮助。
标签: javascript node.js firebase promise google-cloud-firestore