异步:在回调内部的 For 之后获取空数组

Async : Get empty array after For inside the callback

我尝试将数据库查询的结果存储在一个数组中,但我得到的总是一个空数组。我不太了解 Async 是如何工作的,但我认为这段代码应该可以工作,因为我在完成之前存储了变量

注意:下面也是一个数组,我知道这个问题是因为异步行为,但我不知道如何解决它

代码:

    exports.getfollowingUser = function(req, res){
  followedUser=[];
  following = req.user.follow;

  for (i = 0; i < following.length; i++) { 
    User.find(following[i].followed, function (err, followUser){
    followedUser[i]= followUser;
    });
    }
    console.log(followedUser) // result empty
    res.render('following', {
      followedUser: followedUser 
    });
  };

编辑:1遵循架构

module.exports = mongoose.model('Friendship',{

    follower: String,
    followed: String
});

编辑:2 用户模式

module.exports = mongoose.model('User',{

    email:{
        type: String,
        unique: true,
        lowercase: true },

    password:String,

    profile:{
        fullname: String,
        gender: String,
        role: {type: String, default: 'Autorizado'},
        country: String },

});

注意:我正在尝试获取用户(登录)关注的朋友并在视图中显示他们。

看执行流程:

exports.getfollowingUser = function(req, res){
    followedUser=[];                                                  // 1
    following = req.user.follow;

    for (i = 0; i < following.length; i++) {                          
        User.find(following[i].followed, function (err, followUser){  // 2,3,4
            followedUser[i]= followUser;                              // 7,8,9
        });
    }
    console.log(followedUser) // result empty                         // 5
    res.render('following', {followedUser: followedUser});            // 6
};

如您所见,在您执行 console.log [5] 时,followedUser[i]= followUser 尚未执行 [7,8,9]。这就是你得到空数组的原因。

这是您可以解决的方法

exports.getfollowingUser = function(req, res){
    followedUser=[];                                                  // 1
    following = req.user.follow;

    var counter = 0;
    var length = following.length;

    for (i = 0; i < following.length; i++) {                          
        User.find(following[i].followed, function (err, followUser){  // 2,3,4
            followedUser[i]= followUser;                              // 7,8,9
            counter++;
            if(counter>=length) allDone();                            // 10
        });
    }

    console.log(followedUser) // result empty                         // 5
    res.render('following', {followedUser: followedUser});            // 6        

    function allDone(){
        console.log(followedUser) // result empty                     // 11
        res.render('following', {followedUser: followedUser});        // 12       
    }
};

此处相同的语句,但在 allDone()[11,12] 内,它们将执行您期望它们执行的操作,因为它们在 [7,8,9].

之后执行

这只是为了解释,有更好的库来处理这样的事情:

也有帮助:https://blog.engineyard.com/2015/taming-asynchronous-javascript-with-async

在您的 for 循环中 node 只需向您的数据库发出请求并继续处理。它不等待数据库的结果。这就是异步的工作原理。因此,在您的 for 循环 node 尚未收到来自数据库的结果并且 followedUser 为空之后。要在没有第三方库的情况下解决此问题,您可以执行以下操作:

exports.getfollowingUser = function(req, res){

    findFollowedUser(req.user.follow, function(error, followedUser) {
        console.log(followedUser);
        res.render('following', {
            followedUser: followedUser
        });
    });

    function findFollowedUser(following, callback) {
        var followedUser=[];
        var waiting  = following.length;
        var wasError = false;

        for (var i = 0; i < following.length; i++) {
            User.find(following[i].followed, function (err, followUser){
                if (wasError) {
                    return;
                }

                if (err) {
                    wasError = err;
                    return callback(err);
                }

                followedUser[i]= followUser;
                waiting--;

                if (!waiting) {
                    callback(null, followedUser);
                }
            });
        }
    }
};

另一种方法(我认为更好)是使用一些流控制库。例如:

我个人的喜好:bluebird - 极快的承诺实现。实际上 promises 是即将推出的 javascript 标准。所以我建议你仔细看看它。

另外,我建议您观看 this video。这是对 javascript 异步模型(事件循环如何工作)的非常简化的解释。