从forEach推送数组并传递给res

时间:2014-06-24 05:25:18

标签: javascript callback sails.js

我对javascript和sails都很陌生。我对javascript的回调感到有些困惑。现在我的控制器有这个方法:

test: function(req, res) {
  var arr = [], someId = [15,16,7];
  someId.forEach(function(val, idx) {
    var temp = {};
    User.find({userId: val}).exec(function(err, usr) {
      Profile.find({profileId: usr.profId}).exec(function(err, prof) {
        temp.name = prof.fullName();
        temp.email = usr.email;
        ...
        arr.push(temp);
        res.json(arr);
      })
    })
  })
}

一切顺利但json响应只发送第一个值而不是最后一个,所以我假设res.json在回调执行期间只传递了第一个arr.push。我如何以及在何处调用res.json,以便它仅在回调完成时才会执行。感谢

3 个答案:

答案 0 :(得分:1)

你必须等到所有的回调都完成。一种简单的方法是:每次Profile.find回调运行时,通过检查arr的长度来检查这是否是最后一个。

someId.forEach(function(val, idx) {
    User.find({userId: val}).exec(function(err, usr) {
      Profile.find({profileId: usr.profId}).exec(function(err, prof) {
        var temp = {};
        temp.name = prof.fullName();
        temp.email = usr.email;
        ...
        arr.push(temp);

         // if arr is now full, send it; otherwise, wait for more
        if(arr.length == someId.length) { res.json(arr); }
      })
    })
})

但是,你说你不知道"完成"数组直到您查询Users。这里的解决方案是首先查询所有用户,然后在以下后查询配置文件:

var usersProcessedCount = 0, matchedUsers = [];
someId.forEach(function(val, idx) {
    User.find({userId: val, status: 1}).exec(function(err, usr) {
      if(usr != null) { matchedUsers.push(usr); }
      if(++usersProcessedCount == someId.length) { fetchProfiles(); }
    })
})

function fetchProfiles() {
    matchedUsers.forEach(val, idx) {
      Profile.find({profileId: val.profId}).exec(function(err, prof) {
        var temp = {};
        temp.name = prof.fullName();
        temp.email = val.email;
        ...
        arr.push(temp);

         // if arr is now full, send it; otherwise, wait for more
        if(arr.length == matchedUsers.length) { res.json(arr); }
      })
    });
}

这里我们将符合条件的所有用户存储在一个数组中,然后,当我们处理完所有候选ID后,我们调用fetchProfiles,它会遍历匹配用户列表。

答案 1 :(得分:0)

您可以使用Waterline的内置"" -query语法来简化查询:如果您为数组设置条件值,它将搜索其值为的所有记录字段匹配数组中的一个。所以:

// Find all users whose ID is in the someId array
User.find({userId: someId}).exec(function(err, users) {

    if (err) {return res.serverError(err);

    // Get the profile IDs of those users using Lodash "pluck"
    var profileIds = _.pluck(users, 'profId');

    // Find all Profile records with those IDs
    Profile.find({profileId: profileIds}).exec(function(err, profiles) {

        if (err) {return res.serverError(err);

        // Use Array.map to transform the profiles array data
        var results = profiles.map(function(profile) {
            // Use Lodash to get the user with this profile ID
            var user = _.find(users, {profId: profile.profileId});
            return {name: profile.fullName(), email: user.email};
        });
        return res.json(results);

    });


});

请注意,_(Lodash)默认情况下由Sails全球化,因此您可以在任何控制器,模型或服务中使用它。

另一种方法是使用async library(也由Sails全球化)以更线性的方式重新组织代码,而不是使用嵌套的回调。

如果您正在使用Sails v0.10.x,您可能还会考虑使用associations直接关联用户和个人资料记录;然后你就能做到:

User.find({userId: someId}).populate('profile').exec(...);

获得您需要的一切。

答案 2 :(得分:-1)

test: function(req, res) {
  var arr = [], someId = [15,16,7];
  someId.forEach(function(val, idx) {
    var temp = {};
    User.find({userId: val}).exec(function(err, usr) {
      Profile.find({profileId: usr.profId}).exec(function(err, prof) {
        temp.name = prof.fullName();
        temp.email = usr.email;
        ...
        arr.push(temp);
      })
    })
  })
  res.json(arr);
}

你没有到达循环的结尾。完成第一项

后,您已经传递了“ARR”的值