在Node.js中链接异步函数的正确方法是什么?

时间:2012-03-01 04:02:58

标签: javascript node.js express mongoose

我有一个有趣的案例,我需要使用Mongoose在MongoDB中进行一些查询,但是在我完成所有这些查询之前,响应才会返回。

我有两种文档类型,列表和项目。在一个特定的调用中,我需要获取特定用户的所有列表,然后迭代它们中的每一个并获取所有项目并在返回之前将它们附加到适当的列表。

List.find({'user_id': req.params.user_id}, function(err, docs){
  if (!err) {
    if (docs) {

      var results = [];

      _und.each(docs, function(value, key) {

        var list = value.toObject();
        list.items = [];

        Item.find({'list_id': value._id}, function(err, docs) {
          if (!err) {
            _und.each(docs, function(value, key) { list.items.push(value.toObject()); });
            results.push(list);
          }
          else {
            console.log(err);
          }
        });
      });

      res.send(results);

(_ und是我如何导入underscore.js)

显然问题是回调,因为有多个循环,我无法在回调中返回。

也许这是我需要提前计算并在每次迭代时检查它以决定何时返回结果的情况。这看起来并不优雅。

2 个答案:

答案 0 :(得分:2)

代码解决方案

首先问题在于代码。您在Item.find查询完成之前发送结果。你可以很容易地解决这个问题

var count = docs.length + 1;
next()
_und.each(docs, function(value, key) {

    var list = value.toObject();
    list.items = [];

    Item.find({
        'list_id': value._id
    }, function(err, docs) {
        if (!err) {
            _und.each(docs, function(value, key) {
                list.items.push(value.toObject());
            });
            // push asynchronous
            results.push(list);
            next()
        }
        else {
            console.log(err);
        }
    });
});

function next() {
    --count === 0 && finish()
}

function finish() {
    res.send(results)
}​

最简单的方法是引用计数,默认计数为文档数。然后,每当你完成一个项目,你就会调用next并将计数减一。

完成所有项目后,您的计数应为零。请注意,我们会.length + 1并立即致电next。这种情况反对没有文件的情况,否则什么都不做。

数据库解决方案

最好的解决方案是正确使用mongo。你不应该在你的代码中做有效的连接,它的速度慢,效率低。您应该有一个嵌套文档并对列表进行非规范化。

所以list.items = [Item, Item, ...]

另外,避免猫鼬,效率低下,使用原生的mongo驱动程序。

答案 1 :(得分:1)

我使用这个模块: https://github.com/caolan/async