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

Jer*_*oen 14 javascript foreach asynchronous synchronous node.js

我目前正在与3个朋友一起使用nodeJs,expressJs,MongoDB,html5进行一个项目......由于我们对这些技术还不熟悉,我们遇到了一些问题.我无法找到解决方案的一个大问题是某些代码的异步执行.

我想要为每个循环完成,以便我有一个更新的在线好友列表,然后执行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
});
Run Code Online (Sandbox Code Playgroud)

}

输出如下:

online friends: mark
redirecting
a loop
a loop
a loop
a loop
a loop
a loop
a loop
Run Code Online (Sandbox Code Playgroud)

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

非常感谢!

BFi*_*Fil 15

以下控制台日志:

console.log("a loop");
Run Code Online (Sandbox Code Playgroud)

在回调中

我相信函数OnlineUser.findOne()的回调是异步调用的,这就是为什么代码会在重定向日志之后记录"循环"的原因

在执行完所有循环回调后,应该重定向

就像是:

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
}
Run Code Online (Sandbox Code Playgroud)


小智 6

通过将async包添加到我的项目并将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
      });
    });
  });
}
Run Code Online (Sandbox Code Playgroud)