如何使代码块同步工作

时间:2013-12-04 12:44:15

标签: node.js mongodb asynchronous express

这是我的代码:

server.get(url_prefix + '/user/:user_id/photos', function(req, res, next) {
    if (!req.headers['x-session-id']) {
        res.send({
            status: {
                error: 1,
                message: "Session ID not present in request header"
            }
        })
    } else {
        User.findOne({
            session_id: req.headers['x-session-id']
        }, function(err, user) {
            if (user) {
                var user_id   = req.params.user_id
                Album.find({userId : user_id})
                     .populate('images')
                     .exec(function (err, albums) {
                        if (albums) {
                            albums.forEach(function(album, j) {
                                var album_images   = album.images
                                album_images.forEach(function(image, i) {
                                    Like.findOne({imageID : image._id, userIDs:user._id}, function(err,like){
                                        if(like){
                                            albums[j].images[i].userLike = true;
                                        }
                                    })
                                })
                            })
                            return res.send({
                                status: {
                                    error: 0,
                                    message: "Successful"
                                },
                                data: {
                                    albums: albums
                                }
                            })
                        } else
                            return notify_error(res, "No Results", 1, 404)
                     })
            }
            else {
                res.send({
                    status: {
                        error: 1,
                        message: "Invalid Session ID"
                    }
                })
            }
        })
    }
})

我正在尝试为我的图片数组添加一个额外的值(albums[j].images[i].userLike = true;),该数组位于相册数组中。

问题是return res.send({在我们收到来自foreach的回复之前发送数据

如何使其工作,以便只有在foreach完成所有迭代后return才会发生

2 个答案:

答案 0 :(得分:4)

您必须等待调用res.send,直到您获取每张相册中所有图片的所有相似内容。 E.g。

var pendingImageLikes = album_images.length;
album_images.forEach(function(image, i) {
  Like.findOne({imageID : image._id, userIDs:user._id}, function(err,like){
  if (like) {
    albums[j].images[i].userLike = true;
  }
  if (!--pendingImageLikes) {
    // we fetched all likes
    res.send(
      // ...
    );
  }
});

您可能需要album_images.length === 0的特殊情况。

此外,这并没有考虑到您有多张相册,每张相册都有多张图片。您必须以非常类似的方式延迟res.send才能使其真正起作用。您可能需要考虑使用流程控制库,如first(或您的任何其他偏好,只需搜索“流控制库”),以使这更容易。

此外,您可能需要考虑不依赖分号插入并手动键入分号。它可以防止模糊表达,使代码更容易阅读。

答案 1 :(得分:2)

由于您需要等待代码完成所有find操作,我建议您考虑使用async包,特别是each({{{ 3}})。它使得使用异步循环更清晰,尤其是在处理MongoDB文档和查询时。有许多不错的功能,包括顺序执行reference函数或series的功能(当你想执行一系列,但是逐步传递结果时)。

> npm install async

添加到您的模块:

var async = require("async");

您的代码看起来像这样:

albums.forEach(function(album, j) {
    async.each(album.images, function(album, done) {
        Like.findOne({imageID: image._id, userIDs:user._id}, function(err, like){
            if(!err && like){
                albums[j].images[i].userLike = true;
            }
            done(err); // callback that this one has finished
        })
    })
    }, function (err) { // called when all iterations have called done()
        if (!err) {
            return res.send({
                status: {
                    error: 0,
                    message: "Successful"
                },
                data: {
                    albums: albums
                }
            });
        } 
        return notify_error(res, "No Results", 1, 404);
    });
});