等待解决多个回调

时间:2015-03-26 07:54:02

标签: node.js mongodb callback mongoose promise

我尝试使用mongoose从一次调用中获取ID。之后,每个ID都用于进行另一个返回多个对象的调用。我正在尝试获取所有这些对象。

我目前的尝试看起来像这样:

  var members;
  var memberTimes = [];

  // Use the Group model to find a specific group
  Group.find({
    members: {
      $elemMatch: {
        $eq: req.user._id
      }
    },
    _id: req.params.group_id
  }, function(err, group) {
    if (err) {
      res.send(err);
    } else if (!group) {
      //res.send(new Error("User not in group or it does not exist"));
    }

    members = group[0].members;

    for (var member of members) {
      // Use the Time model to find a specific time
      Time.find({
        user_id: member
      }, function(err, times) {
        if (err) {
          res.send(err);
        }

        for (var time of times) {
          memberTimes.push(time);
        }
      });
    }
    //on completion of all above code, execute res.json(memberTimes);
 });

然而,这不起作用,因为我不等待Time#find的所有回调。我已经看过使用promises,但我不确定它是如何使它工作的。

有谁知道如何才能使其发挥作用?

谢谢你, 丹尼尔

2 个答案:

答案 0 :(得分:1)

您需要进行异步循环并等待最终响应。你可以做点什么

var members;

function getTimes(mTimes, times, i, done) {
    console.log("time " + i);
    if (i < times.length) {
      console.log(times[i]);
      mTimes.push(times[i]);
      getTimes(mTimes, times, i + 1, done);
    } else {
      done(mTimes);
    }
  }

  function asyncLoop(memberTimes, members, i, callback) {
    if (i < members.length) {
      Time.find({
        user_id: members[i]
      }, function(err, times) {
        if (err) {
          res.send(err);
        }
        console.log(times);
        getTimes(memberTimes, times, 0, function(result) {
          asyncLoop(memberTimes, members, i + 1, callback);
        });
      });
    } else {
      callback(memberTimes);
    }
  }

  // Use the Group model to find a specific group
  Group.find({
    members: {
      $elemMatch: {
        $eq: req.user._id
      }
    },
    _id: req.params.group_id
  }, function(err, group) {
    if (err) {
      res.send(err);
    } else if (!group) {
      //res.send(new Error("User not in group or it does not exist"));
    }

    members = group[0].members;

    var memberTimes = [];
    asyncLoop(memberTimes, members, 0, function(memberTimes) {
      res.json(memberTimes);
    });
  });

上面的代码可能无法运行,因为我没有运行它,但这就是你如何实现你想要的。

答案 1 :(得分:1)

是的,applying promises听起来不错。

您需要选择an implementationhow to promisify您的find方法调用依赖Promise.all。假设你有一个find函数接受接收器和选项并返回一个承诺 - (编辑)在mongoose中,你很幸运,.exec()似乎已经产生了一个承诺:

function find(model, options) {
  return model.find(options).exec();
}

然后您的代码将如下所示:

find(Group, {
  members: {$elemMatch: {$eq: req.user._id}},
  _id: req.params.group_id
}).then(function(group) {
  if (!group)
    throw new Error("User not in group or it does not exist");

  return Promise.all(group[0].members.map(function(member) {
    return find(Time, {user_id: member});
  }));
}).then(function(memberTimes) {
  res.json(memberTimes);
}, function(err) {
  res.send(err);
});

在这里,{{3}}是等待多个time-find-promises(并行)解决的部分。