NodeJs,javascript:.forEach似乎是asynchronous的? 需要同步

我目前正在与3个朋友一起使用nodeJs,expressJs,MongoDB,html5,…因为我们对这些技术相当陌生,所以遇到了一些问题。 我找不到解决scheme的一个大问题是某些代码的asynchronous执行。

我想每一个循环完成,以便我有一个更新的在线朋友列表,并执行res.render(我通过在线朋友列表),因为目前它完成res.render之前完成循环。 码:

function onlineFriends(req, res) { var onlinefriends = new Array(); onlinefriends.push("mark"); FriendList.findOne({ owner: req.session.username }, function (err, friendlist) { friendlist.friends.forEach(function (friend) { // here forEach starts OnlineUser.findOne({ userName: friend }, function (err, onlineFriend) { if (onlineFriend != null) { onlinefriends.push(onlineFriend.userName); console.log("a loop"); } }); }); console.log("online friends: " + onlinefriends); console.log("redirecting"); res.render('index', { // this is still inside the forEach function friendlist: friendlist.friends, onlinefriendlist: onlinefriends, username: req.session.username });// and here it ends }); 

}

输出将如下所示:

 online friends: mark redirecting a loop a loop a loop a loop a loop a loop a loop 

正如这里讨论的( JavaScript,Node.js:是Array.forEachasynchronous? ),答案是for-each是阻塞的,但在我的例子中,它似乎是非阻塞的,因为它在执行res.render完成循环? 我怎样才能确保每一个完成,所以我有一个最新的onlinefriends列表(和friendlist),我可以传递给res.render而不是res.render发生的方式之前for-each循环完成(这给了我一个不正确的在线用户列表)?

非常感谢!

以下控制台日志:

 console.log("a loop"); 

在一个callback里面

我相信函数OnlineUser.findOne()的callback是asynchronous调用的,这就是为什么代码会在redirect日志之后logging“一个循环”

在所有的循环callback执行之后,你应该把redirect

就像是:

 var count = 0; friendlist.friends.forEach(function (friend) { // here forEach starts OnlineUser.findOne({ userName: friend }, function (err, onlineFriend) { count++; if (onlineFriend != null) { onlinefriends.push(onlineFriend.userName); console.log("a loop"); } if(count == friendlist.friends.length) { // check if all callbacks have been called redirect(); } }); }); function redirect() { console.log("online friends: " + onlinefriends); console.log("redirecting"); res.render('index', { // this is still inside the forEach function friendlist: friendlist.friends, onlinefriendlist: onlinefriends, username: req.session.username });// and here it ends } 

我能够通过将asynchronous包添加到我的项目并将forEach()更改为async.each()来解决类似的问题。 这样做的好处是可以为应用程序的其他部分提供一种标准的同步方法。

像这样的项目你的项目:

 function onlineFriends(req, res) { var onlinefriends = new Array(); onlinefriends.push("mark"); FriendList.findOne({owner: req.session.username}, function (err, friendlist) { async.each(friendlist.friends, function(friend, callback) { OnlineUser.findOne({userName: friend}, function (err, onlineFriend) { if (onlineFriend != null) { onlinefriends.push(onlineFriend.userName); console.log("a loop"); } callback(); }); }, function(err) { console.log("online friends: " + onlinefriends); console.log("redirecting"); res.render('index', { // this is still inside the forEach function friendlist: friendlist.friends, onlinefriendlist: onlinefriends, username: req.session.username }); }); }); } 

通过jsbeautifier运行你的代码,正确缩进它,并告诉你为什么发生这种情况:

 function onlineFriends(req, res) { var onlinefriends = new Array(); onlinefriends.push("mark"); FriendList.findOne({ owner: req.session.username }, function (err, friendlist) { friendlist.friends.forEach(function (friend) { // here forEach starts console.log("vriend: " + friend); OnlineUser.findOne({ userName: friend }, function (err, onlineFriend) { if (onlineFriend != null) { onlinefriends.push(onlineFriend.userName); console.log("online friends: " + onlinefriends); } }); console.log("nu door verwijzen"); res.render('index', { // this is still inside the forEach function friendlist: friendlist.friends, onlinefriendlist: onlinefriends, username: req.session.username }); }); // and here it ends }); 

所以…总是缩进你的代码,你不会有这样的问题。 一些像Vim这样的编辑器可以用一个简单的缩进( gg=G in vim)缩进你的整个文件。

但是, OnlineUser.findOne()很可能是asynchronous的。 所以即使您将呼叫转移到正确的位置也不会起作用。 请参阅ShadowCloud关于如何解决这个问题的答案 。