我正在尝试使用mongoDB在nodejs中编写“facebook clone”。 我遇到的问题是,每当用户访问用户的个人资料时,他需要获取他的朋友阵列。我这样做的方式是这样的:
router.get("/user/:id/profile", isLoggedIn, (req, res) => {
let friends = [];
User.findById(req.params.id, (err, user) => {
if (err) {
req.flash("error", "There has been an error going to this persons profile.");
res.redirect("back");
} else {
if (user.friends.length > 0) {
for(var i = 0; i < user.friends.length; i++) {
User.findById(user.friends[i], (err, friend) => {
if (err) {
console.log(err);
req.flash("error", "Could not find the friends list")
res.redirect("back")
} else {
friends.unshift({
firstName: friend.firstName,
lastName: friend.lastName,
_id: friend._id
})
console.log(friends)
}
});
}
console.log(friends, "158")
res.render("user", { userData: user, friends: friends })
} else {
// render the page without the friends array.
res.render("user", { userData: user }); // im calling it userData because i have a local template variable called user and i don't want to over-write it
}
}
});
});
然后发生的事情就是我在for循环中执行console.log(朋友)的地方,我得到了包含所有内容的好友数组,但是当我在res.render之前执行console.log(好友)时(“user”)数组为空。任何想法为什么?
答案 0 :(得分:2)
在为node.js编写代码时,您需要习惯异步函数,因为很多addins / classes /代码都使用它。
编码不再是“线性的”,而是在完成前一代码后立即调用函数。
在你的情况下,findById
开始在mongoDB中查找文档的过程,一旦找到它们,它就会调用带参数(err, friend)
的(在你的情况下是匿名的)回调函数。
您对res.render
的通话不在该回调范围内,并会在findById
开始后立即致电。那是早期的
您需要将res.render
放在回调中以获取数据。
编辑:由于for循环,以下代码无法正常运行。我们需要使用Prajvals答案中所示的承诺。请使用他的第二个例子,因为那个有效。
User.findById(user.friends[i], (err, friend) => {
if (err) {
console.log(err);
req.flash("error", "Could not find the friends list")
res.redirect("back")
} else {
friends.unshift({
firstName: friend.firstName,
lastName: friend.lastName,
_id: friend._id
})
console.log(friends);
res.render("user", { userData: user, friends: friends })
}
});
答案 1 :(得分:1)
这是因为节点的异步性质。在回调函数中使用res.render或使用promises将对此进行排序。
没有承诺
User.findById(req.params.id, (err, user) => {
if (err) {
req.flash("error", "There has been an error going to this persons profile.");
res.redirect("back");
} else {
if (user.friends.length > 0) {
for(var i = 0; i < user.friends.length; i++) {
User.findById(user.friends[i], (err, friend) => {
if (err) {
console.log(err);
req.flash("error", "Could not find the friends list")
res.redirect("back")
} else {
friends.unshift({
firstName: friend.firstName,
lastName: friend.lastName,
_id: friend._id
})
console.log(friends)
res.render("user", { userData: user, friends: friends })
}
});
}
console.log(friends, "158")
} else {
// render the page without the friends array.
res.render("user", { userData: user });
}
}
});
有了承诺
User.findById(user.friends[i])
.then((friend) => {
friends.unshift({
firstName: friend.firstName,
lastName: friend.lastName,
_id: friend._id
})
})
.then(()=>{
res.render("user", { userData: user, friends: friends })
})
.catch( err=>{
console.log(err);
req.flash("error", "Could not find the friends list")
res.redirect("back")
})
---- ---- EDIT
现在也可以使用async await。我虽然没有在这里展示。
我写的没有承诺的那个将不起作用。 对于有/无承诺的操作,您需要使用递归方式进行同步而不是for循环。