如何强制javascript不使回调函数并行?

时间:2014-08-06 16:03:04

标签: javascript node.js callback mongoose

我正在使用Node.js构建一个twitter克隆,使用mongoose构建MongoDB。我的Tweet模型包含bodyusercreated字段,其中user是创建推文的用户的ID。现在我正在构建API。我希望当我发出GET请求以接收所有推文(/api/tweets/)的列表但除user字段(仅返回用户的id)之外我想获取整个用户对象这样我就可以在我的前端部分显示有关推文所有者的信息。我最终得到了以下代码。

exports.all = function (req, res, next) {
  Tweet.find({}, function (err, tweets) {
    if (err) return res.json(400, err);

    var response = [];
    tweets.forEach(function (element, index, array) {
      var tweet = {};
      tweet._id = element._id;
      tweet.created = element.created;
      tweet.body = element.body;
      User.findById(element.user, function (err, user) { // <- This line
        if (err) return res.json(400, err);

        tweet.user = user;
      });

      response.push(tweet);
    });

    return res.json(response);
  });
};

它完美无缺,但它不会添加用户信息。问题出在我标记的行中。当javascript到达那一行时,它会尝试使它成为&#34; parallel&#34;并继续执行代码而不执行回调函数。但随后它推送了尚未拥有用户信息的tweet对象。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

您将要使用async库。它会让你的生活更轻松。

// inside `Tweet.find`
async.each(tweets, function(done) {
    // do stuff to tweets
    User.findById(element.user, function(err, user){
        if (err) return done(err);
        // do stuff with user
        done();
    });
}, function(err) {
   // called when done
   res.json(response);
});

答案 1 :(得分:0)

问题在于res.json发送了响应,因此调用findById并不重要。一切都完成后,您需要致电res.json

您可以通过多种方式执行此操作,但使用现有代码最简单的方法就是保留一个计数器:

var tweetCount = 0;

tweets.forEach(/* snip */) {
    User.findById(element.user, function (err, user) {
        tweet.user = user;
        tweetCount++;
        response.push(tweet);

        if (tweetCount == tweets.length) {
            res.json(response);
        }
    });
});

答案 2 :(得分:0)

您可以将 Q 承诺库用于 同步 。它简单易用。

只有在整个承诺链完成后才会发送响应

var result = Q();
tweets.forEach(function (tweet, i) {
     result = result.then(function () {
         // do your stuff
     }

result.then(function () {
    res.json(response);  //successfully completed
});