Javascript 从forEach推送数组并传递到res
我对javascript和sails都是新手。我对javascript的回调有点困惑。现在我的控制器有以下方法:Javascript 从forEach推送数组并传递到res,javascript,callback,sails.js,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
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
,使其仅在回调完成时执行。谢谢
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”的值您必须等待所有回调完成。一个简单的方法是:每次运行
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); }
})
})
})
但是,在查询用户之前,您不知道“finished”数组有多长。这里的解决方案是先查询所有用户,然后再查询配置文件:
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
,它在匹配的用户列表上循环。您可以使用Waterline内置的“in”-查询语法简化查询:如果您将条件值设置为数组,它将搜索该字段的值与数组中的值匹配的所有记录。因此:
// 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全球化,因此您可以在任何控制器、模型或服务中使用它
另一种方法是使用(也被Sails全球化)以更线性的方式重新组织代码,而不是使用嵌套回调
如果您使用的是帆V0.10.x,您也可以考虑使用直接关联用户和配置文件记录;然后你就可以做:
User.find({userId: someId}).populate('profile').exec(...);
获取所需的一切。我已经尝试过这个方法,效果很好,但这里的问题是,如果在查询用户时设置一些约束会怎么样。例如,User.find({userId:val})。where({'status':1})
usr长度与arr的长度不匹配。是否有其他解决方法?@mateeow编辑以解决您对筛选的担忧:构建一个筛选UER数组,然后根据该筛选列表执行配置文件的提取(并使用该列表的长度来确定完成的时间)。我认为这不起作用,因为usersProcessedCount只会增加到usr的长度,并且不是所有用户都具有状态1,如果(++usersProcessedCount==someId.length,则
将不会被删除true@mateeyow也许我误解了Sails处理空结果的方式。我假设没有找到匹配的请求(即记录的状态不是1)将使用usr
的null
值运行回调;因此,usetsProcessedCount
将在匹配和非匹配查询上递增。您是否建议对于非匹配记录,回调根本不会运行?这似乎是错误的,因为您无法区分无结果请求和非常慢的查询请求。模型的exec
方法是异步的,因此此代码在任何回调运行之前发送arr
。您的代码启动所有请求,但它不会等待exec
回调运行;因此,它在填充任何数据之前发送回arr
。