【问题标题】:Async db calls using recursion使用递归的异步数据库调用
【发布时间】:2015-06-19 20:33:48
【问题描述】:

我需要递归地下降一个链表数据库树

item 1-> item 2
      -> item 3 -> item 4
      -> item 5 -> item 6 -> item 7
      -> item 8

我的伪代码是

var getItems = function(itemid) {
    db.getitem(itemid, function(item) {

    item.items.forEach(function(subitem) {
        getItems(subitem.id)
    })
})

getItems(1)

但是,db.getItem 是一个异步函数

我想返回一个与图相同结构的JS对象给顶层调用者

实现这一目标的最佳方法是什么?我不知道前面的结构(即不知道每个项目的项目数,或树中任何分支的深度),所以我不知道需要处理的项目数

我尝试了异步库的各种方法,但似乎都没有处理递归

【问题讨论】:

  • 递归取决于父值,即调用者将传递值,正如您所说的那样,您的方法是异步的,这不是建议的方法。您需要保持操作同步。
  • 我假设你只需要某个节点的子节点,而不是所有的树,而且树很大。因为如果我们谈论的是 10-100 个节点,那么将它们全部拉出并用 JS 构建树“客户端”会更快/更容易。也许还缓存生成的树? 另外,除了github.com/luciotato/waitfor 之外,真的没有办法进行真正的“同步”数据库调用AFAIK(stackoverflow.com/questions/26839320/…),但这确实违背了JS 和NodeJS 的全部意义。
  • 如果必须,请使用事件 (nodejs.org/api/events.html) 而不是异步包。

标签: javascript node.js asynchronous recursion


【解决方案1】:

这就是强并发原语大放异彩的地方。

Promises 让你很容易做到这一点:

// with bluebird this is var getItem = Promise.promisify(db.getitem);
var getItem = function(itemid){
     return new Promise(function(resolve, reject){
        db.getitem(itemid, function(err, data){
            if(err) reject(err);
            else resolve(data);
        });
     });
};

这会让你做什么:

var getItems = function(itemid) {
    return getItem(itemid).then(function(item){ // get the first
       return Promise.all(item.items.forEach(function(subItem){
           return getItems(subitem.id);
       });
    }).then(function(subItems){
        var obj = {};
        obj[itemid] = subItems; // set the reference to subItems
        return obj; // return an object containing the relationship
    });
};


getItems(1).then(function(obj){
   // obj now contains the map as you describe in your problem description
});

下面是async 的样子:

var getItems = function(itemid, callback){
   db.getitem(itemid, function(err, item){
       if(err) return callback(err, null);
       async.map(item.items, function(subitem, cb){
           getItems(subitem.id, cb);
       }, function(err, results){
           if(err) return callback(err, null);
           var obj = {};
           obj[itemid] = result;
           return callback(null, obj);
       });
   });
};

它已经很接近了,但我认为它不如承诺版本好。

【讨论】:

  • 该死的,编码很好。完美解决了我的问题。如果可以的话,有一百万个赞;)
猜你喜欢
  • 2016-09-21
  • 2015-08-27
  • 2018-01-30
  • 2017-10-28
  • 2017-03-12
  • 2013-12-07
  • 2017-06-27
  • 2014-12-18
  • 2020-02-10
相关资源
最近更新 更多