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.

访问单个用户的宠物