我对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
,以便它仅在回调完成时才会执行。感谢
答案 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”的值