Muh*_*las 2 javascript node.js promise firebase es6-promise
我尝试链接几个按顺序执行的 then 函数,但最后一个 .then() 是在前一个 .then() 执行完成之前执行的,因此它发送了一个空的有效负载。以下是片段:
router.get("/selectedHotels", function(req, res) {
let payload = [];
return collectionRef
.where("isOwner", "==", true)
.get() //fetches owners
.then(snapshot => {
snapshot.forEach(user => {
console.log("User", user);
collectionRef
.doc(user.id)
.collection("venues")
.get() // fetches hotels from owners
.then(snapshot => {
snapshot.forEach(doc => {
if (
doc.data().location.long == req.query.long &&
doc.data().location.lat == req.query.lat
) {
console.log(doc.id, "=>", doc.data());
payload.push({
id: doc.id,
data: doc.data()
});
}
});
})
.catch(err => {
console.log("No hotels of this user", err);
});
});
})
.then(() => {
console.log("Payload", payload);
response(res, 200, "Okay", payload, "Selected hotels");
})
.catch(err => {
console.log("Error getting documents", err);
response(res, 404, "Data not found", null, "No data available");
});
});
Run Code Online (Sandbox Code Playgroud)
有什么建议么?谢谢
forEach
您的主要错误是您的嵌套承诺链中间有一个非承诺返回函数。
router.get('/selectedHotels',function(req,res){
let payload = [];
return collectionRef.where(...).get()
.then((snapshot)=>{
snapshot.forEach(user => {
// ^^^^^^^^^^^^^^^^^ this means the outer promise doesn't wait for this iteration to finish
// ...
Run Code Online (Sandbox Code Playgroud)
最简单的解决方法是映射您的 Promise 数组,将它们传递给Promise.all
并返回它们:
router.get('/selectedHotels',function(req,res){
let payload = [];
return collectionRef.where(...).get()
.then((snapshot)=> {
return Promise.all(snapshot.map(
// ...
return collectionRef.doc(user.id).collection('venues').get()
.then(...)
))
Run Code Online (Sandbox Code Playgroud)
话虽这么说,像这样的嵌套承诺是一种反模式。Promise 链允许我们通过 then 回调传播值,因此无需嵌套它们。
相反,您应该将它们垂直链接起来。
以下是如何执行此操作的示例:
router.get("/selectedHotels", function(req, res) {
return collectionRef
.where("isOwner", "==", true)
.get() //fetches owners
// portion of the chain that fetches hotels from owners
// and propagates it further
.then(snapshot =>
Promise.all(
snapshot.map(user =>
collectionRef
.doc(user.id)
.collection("venues")
.get()
)
)
)
// this portion of the chain has the hotels
// it filters them by the req query params
// then propagates the payload array
// (no need for global array)
.then(snapshot =>
snapshot
.filter(
doc =>
doc.data().location.long == req.query.long &&
doc.data().location.lat == req.query.lat
)
.map(doc => ({ id: doc.id, data: doc.data() }))
)
// this part of the chain has the same payload as you intended
.then(payload => {
console.log("Payload", payload);
response(res, 200, "Okay", payload, "Selected hotels");
})
.catch(err => {
console.log("Error getting documents", err);
response(res, 404, "Data not found", null, "No data available");
});
});
Run Code Online (Sandbox Code Playgroud)