调用res.render()后会发生Mongoose发现吗?

时间:2018-06-11 09:00:33

标签: javascript node.js express mongoose

我正在尝试使用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”)数组为空。任何想法为什么?

2 个答案:

答案 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循环。