如何在异步调用期间填充数组并将其发送到响应对象中

Posted

技术标签:

【中文标题】如何在异步调用期间填充数组并将其发送到响应对象中【英文标题】:How can I populate an array during an async call and send it in a response object 【发布时间】:2015-08-04 22:56:45 【问题描述】:

这是我正在尝试做的一个示例,检索 mongo db 中的所有帖子,为每个帖子填充作者,然后使用作者对象从 Cloudinary 检索个人资料图片。

这样做的正确方法是什么?我尝试了多种填充数组并在响应中发送它们的方法,但是由于异步调用,它们在发送 res 之前永远不会运行。

router.get('/posts',auth, function(req, res, next) 
  //var id = req.payload._id;
  Post.find(function(err, posts)
    if(err) return next(err); 
    posts.forEach(function(post)
      post.populate('author',function(err,post)
        post.image = cloudinary.image("v"+post.author.avatarVersion+"/profile/"+post.author._id,
          width:100, height:100,crop:'thumb',gravity:'face',radius:'max'
        )
        //here the post object is updated
        console.log(post)
      )
    )
    //res.json(some posts array);
  );
);

感谢 Dan Moldovan 的解决方案!

router.get('/posts',auth, function(req, res, next) 
  var id = req.payload._id;

  Post.find().populate('author').exec(function(err,posts)
    if(err) return next(err); 
    var updatedPosts = [];
    posts.forEach(function(post)
      post.image = cloudinary.image("v"+post.author.avatarVersion+"/profile/"+post.author._id,
          width:100, height:100,crop:'thumb',gravity:'face',radius:'max'
      )
      updatedPosts.push(post);
    )
    res.json(updatedPosts);
  )

【问题讨论】:

【参考方案1】:

您可以将populate 查询链接到第一个查询,然后进行最终回调,例如

Post.find().populate('author').exec(function (err, posts) 
    if(err) return next(err); 
    posts.forEach(function(post)
         // here each post will already have author appended
    );
);

【讨论】:

嗨,丹,感谢您的回复!这可以使填充更有效率。但是我仍然无法将更新后的帖子数组放入 res.json() 中。 forEach 是同步的,因此您应该能够在 forEach 之后立即成功地 res.json 数组【参考方案2】:

Dan 的解决方案是正确的,但我想解释一下您遇到的问题。因为post.populate()是数据库调用,所以代码是异步的。这意味着forEach() 中的下一个帖子将在.populate() 完成上一个帖子之前开始运行。这意味着并非所有帖子都会在res.json() 执行之前完成。一个解决方案(在这种情况下不需要,但可以由您当前的代码使用)是使用async library:

var async = require("async");

router.get('/posts',auth, function(req, res, next) 
    var id = req.payload._id;

    Post.find(function (err, posts) 
        if (err) 
            return next(err);
        

        // This is a forEach that waits until all posts are populated before moving on
        async.each(posts, function (currentPost, postCallback) 

            currentPost.populate("author", function (err, post) 

                if (err) 
                    return postCallback(err);
                
                post.image = cloudinary.image("v" + post.author.avatarVersion + "/profile/" + post.author._id, 
                    width: 100, height: 100, crop: 'thumb', gravity: 'face', radius: 'max'
                );
                // the callback function for the current post
                postCallback(); 
            );
        , function (error) 
            // the final callback function once all postCallback()'s have been executed, or an error

            if (error) 
                return next(error);
            
            // here, everything is finished
            res.json(posts);
        );
    );
);

同样,Dan 的解决方案是正确的,所以不要使用此代码。当您遇到此类问题时请记住这一点。

【讨论】:

谢谢!我敢肯定这会派上用场。

以上是关于如何在异步调用期间填充数组并将其发送到响应对象中的主要内容,如果未能解决你的问题,请参考以下文章

循环内的异步函数完成后如何调用函数?

需要来自 txt 文件的数据,以逗号分隔,以使用现有类中的对象填充数组列表

如何从异步函数中获取数组的所有值

将响应 NSArray 转换为对象数组 swift3

Python:如何创建一个函数来从 url 获取数据并将其异步发送到其他位置?

如何将复杂的 C# 类序列化为 XML 并将其作为 .net 核心 API 的响应发送?