forloop中的sailsJS .exec()不起作用

时间:2015-01-23 16:36:14

标签: sails.js

我有一个这样的模型:

\**
* 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仅在回调之后执行,在这种情况下会导致返回过早。 Sails中有什么可以解决这个问题吗?否则,无法使用for循环进行查询。我对JS的工作方式还很新。任何帮助表示赞赏。谢谢(:

2 个答案:

答案 0 :(得分:2)

这不是一个Sails问题,它是Node的一个普遍问题,当您了解有关异步编程的更多信息时,您会遇到它。如果你在" node.js中搜索StackOverflow异步循环"你会找到dozens of questions and answers。问题是您在同步.exec()循环内调用异步函数(for),因此循环的所有迭代(以及return response)都在任何循环之前发生调用实际的回调(function(err, pets)函数)。

解决此问题的最简单方法是使用像async这样的库来异步运行循环。由于这个原因,默认情况下Sails包含并全局化async,所以你可以这样做:

// 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(...)

答案 1 :(得分:2)

如果您使用Sails .10或更高版本,您可以使用模型关联来解决问题,方法略有不同。事实上,他们在documentation中详述了一个非常相似的用例。

如果您以这种方式设置模型:

对myApp / API /模型/ pet.js

module.exports = {
    attributes: {
        name:'STRING',
        // include whatever other attributes
        owner:{
            model:'user'
        }
    }
}

对myApp / API /模型/ 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访问单个用户的宠物。