forloop 中的 sailsJS .exec() 不起作用
sailsJS .exec() within forloop doesn't work
我有一个这样的模型:
\**
* user.petIds = ["1","2","3","4"];
*\
getPets: function(users){
var response = [];
users.forEach(function(user){
Pet.find(users[i].petIds).exec(function(err, pets){
if(err) return null;
console.log("index: "+i);
response.push({ name: users[i].name, pets: pets});
});
});
return response;
}
我想从一组用户的宠物 ID 数组中获取每只宠物。但是,exec 仅在回调之后执行,在这种情况下会过早地导致 return。 Sails 中有什么可以解决这个问题的吗?否则无法使用for循环查询。我对 JS 的工作方式还很陌生。任何帮助表示赞赏。谢谢 (:
这不是 Sails 问题,而是 Node 的一个普遍问题,您在学习更多有关异步编程的知识时会遇到这个问题。如果您在 Whosebug 中搜索 "node.js asynchronous loop",您会找到 dozens of questions and answers。问题是您在同步 for
循环中调用异步函数 (.exec()
),因此循环的所有迭代(和 return response
)都发生在任何调用实际回调(function(err, pets)
函数)。
解决此问题的最简单方法是使用 async
之类的库以异步方式 运行 循环。正是出于这个原因,async
默认情况下被 Sails 包含和全球化,因此您可以这样做:
// Note the new second argument to "getPets", since this is
// an asynchronous function it requires a callback
getPets: function(users, getPetsCb){
// Asynchronous "map" call to transform users
async.map(users, function iterator (user, mapCb){
// Get the user's pets
Pet.find(user.petIds).exec(function(err, pets) {
// In case of error pass it to the callback, which
// will abort the loop
if(err) return mapCb(err);
// Use "null" as the first arg to indicate no error has
// occurred, and pass the transformed user as the second
// to add it to the array
return mapCb(null, { name: user.name, pets: pets});
});
},
// Pass the outer callback as the 3rd argument to async.map
// to pass the final error state and array of transformed
// users to whoever called "getPets"
getPetsCb);
}
阅读 full docs for async.map
here,以及所有其他有趣的 async
方法。
另请注意,在您的特定情况下,您可以使用 Sails associations 来模拟 User 和 Pet 之间的关系,并通过一个查询获取所有这些信息:User.find(...).populate('pets').exec(...)
!
如果您使用 Sails .10 或更高版本,您可以使用模型关联通过稍微不同地处理问题来处理此问题。事实上,他们在 documentation.
中详细介绍了一个非常相似的用例
如果您以这种方式设置模型:
myApp/api/models/pet.js
module.exports = {
attributes: {
name:'STRING',
// include whatever other attributes
owner:{
model:'user'
}
}
}
myApp/api/models/user.js
module.exports = {
attributes: {
name:'STRING',
// other attributes you may want included here
pets:{
collection: 'pet',
via: 'owner'
}
}
}
然后在您的控制器中,您可以使用以下命令查找给定用户的所有宠物:
getPets: function(req, res) {
User.find()
.where({id: users})
.populate('pets')
.exec(function(err, users) {
if (err) throw err; // do error handling here
return res.json({
users: users
});
});
}
通过这样做,发回给您的 JSON 包含每个用户,以及该用户的所有宠物,如此处所示。
{
users:
[{
pets:
[ { name: 'Spot',
id: 2,
createdAt: Tue Feb 11 2014 17:58:04 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 17:58:04 GMT-0600 (CST),
owner: 1 },
{ name: 'Sparky',
id: 4,
createdAt: Tue Feb 11 2014 18:02:58 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 18:02:58 GMT-0600 (CST),
owner: 1 } ],
name: 'Mike',
createdAt: Tue Feb 11 2014 17:49:04 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 17:49:04 GMT-0600 (CST),
id: 1
}]
}
然后您可以使用返回的 JSON.
访问单个用户的宠物
我有一个这样的模型:
\**
* user.petIds = ["1","2","3","4"];
*\
getPets: function(users){
var response = [];
users.forEach(function(user){
Pet.find(users[i].petIds).exec(function(err, pets){
if(err) return null;
console.log("index: "+i);
response.push({ name: users[i].name, pets: pets});
});
});
return response;
}
我想从一组用户的宠物 ID 数组中获取每只宠物。但是,exec 仅在回调之后执行,在这种情况下会过早地导致 return。 Sails 中有什么可以解决这个问题的吗?否则无法使用for循环查询。我对 JS 的工作方式还很陌生。任何帮助表示赞赏。谢谢 (:
这不是 Sails 问题,而是 Node 的一个普遍问题,您在学习更多有关异步编程的知识时会遇到这个问题。如果您在 Whosebug 中搜索 "node.js asynchronous loop",您会找到 dozens of questions and answers。问题是您在同步 for
循环中调用异步函数 (.exec()
),因此循环的所有迭代(和 return response
)都发生在任何调用实际回调(function(err, pets)
函数)。
解决此问题的最简单方法是使用 async
之类的库以异步方式 运行 循环。正是出于这个原因,async
默认情况下被 Sails 包含和全球化,因此您可以这样做:
// Note the new second argument to "getPets", since this is
// an asynchronous function it requires a callback
getPets: function(users, getPetsCb){
// Asynchronous "map" call to transform users
async.map(users, function iterator (user, mapCb){
// Get the user's pets
Pet.find(user.petIds).exec(function(err, pets) {
// In case of error pass it to the callback, which
// will abort the loop
if(err) return mapCb(err);
// Use "null" as the first arg to indicate no error has
// occurred, and pass the transformed user as the second
// to add it to the array
return mapCb(null, { name: user.name, pets: pets});
});
},
// Pass the outer callback as the 3rd argument to async.map
// to pass the final error state and array of transformed
// users to whoever called "getPets"
getPetsCb);
}
阅读 full docs for async.map
here,以及所有其他有趣的 async
方法。
另请注意,在您的特定情况下,您可以使用 Sails associations 来模拟 User 和 Pet 之间的关系,并通过一个查询获取所有这些信息:User.find(...).populate('pets').exec(...)
!
如果您使用 Sails .10 或更高版本,您可以使用模型关联通过稍微不同地处理问题来处理此问题。事实上,他们在 documentation.
中详细介绍了一个非常相似的用例如果您以这种方式设置模型:
myApp/api/models/pet.js
module.exports = {
attributes: {
name:'STRING',
// include whatever other attributes
owner:{
model:'user'
}
}
}
myApp/api/models/user.js
module.exports = {
attributes: {
name:'STRING',
// other attributes you may want included here
pets:{
collection: 'pet',
via: 'owner'
}
}
}
然后在您的控制器中,您可以使用以下命令查找给定用户的所有宠物:
getPets: function(req, res) {
User.find()
.where({id: users})
.populate('pets')
.exec(function(err, users) {
if (err) throw err; // do error handling here
return res.json({
users: users
});
});
}
通过这样做,发回给您的 JSON 包含每个用户,以及该用户的所有宠物,如此处所示。
{
users:
[{
pets:
[ { name: 'Spot',
id: 2,
createdAt: Tue Feb 11 2014 17:58:04 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 17:58:04 GMT-0600 (CST),
owner: 1 },
{ name: 'Sparky',
id: 4,
createdAt: Tue Feb 11 2014 18:02:58 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 18:02:58 GMT-0600 (CST),
owner: 1 } ],
name: 'Mike',
createdAt: Tue Feb 11 2014 17:49:04 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 17:49:04 GMT-0600 (CST),
id: 1
}]
}
然后您可以使用返回的 JSON.
访问单个用户的宠物