什么's是在Node.js中链接异步函数的正确方式

What's the proper way of chaining async functions in Node.js?

本文关键字:函数 异步 链接 方式 js Node 是在 什么      更新时间:2023-09-26

我有一个有趣的案例,我需要使用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是我导入下划线.js的方式)

很明显,问题是回调,由于有多个循环,我无法在回调中返回。

也许在这种情况下,我需要提前获得计数,并在每次迭代时进行检查,以决定何时返回结果。不过这看起来并不优雅。

代码解决方案

首先,问题在于代码。您在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, ...]

除此之外,避免mongose,它效率低下,使用本地mongo驱动程序。

我与此模块一起使用:https://github.com/caolan/async