异步递归调用让我疯狂

时间:2016-01-21 20:51:51

标签: javascript asynchronous recursion loopbackjs

我有一个分层系统。一个类别有一个parentid(如果它是一个根类别,则为0)。

类别DB中的示例行:

   name    |   id | parentid 
-----------+------+----------
 Label     |   71 |        8

我需要获得给定类别的所有子类别。所有人不仅指一个类别的直接孩子,而且指所有孩子的每个孩子。

我以前做过递归的东西,但是在同步环境中,并且它让我感到它不完全以同样的方式工作。

我知道我离工作解决方案并不遥远,但它并不适用于所有情况。注意:删除所有调试日志行不会混淆问题。

此外,欢迎任何简化和/或优化。例如,我不喜欢有两个回调,一个递归回调,最后一个...(但可能是由于异步它需要这样?)。

整个事情应该返回给定类别的所有子类别的ID的数组(allCats)。

此当前解决方案适用于没有子级的单个类别,并且一级层次结构向下(并且allCats正确包含所有ID)。它在两个级别失败(永远不会调用最终的回调,因此cnt未正确更新?)。

通过致电Category.getAllSubCategories(categoryId);

启动搜索
  Category.getSubCategories = function(cat, cnt, fullCats, cb, finalCb) {        
    Category.find({where: {parentId: cat.id}}, function(err, cats) {
      if (err) {
        cb(err);
      }   
      if (cats.length > 0) {
        var ids = []; 
        for (var i=0; i<cats.length; i++) {
          ids.push(cats[i].id);
        }
        fullCats = fullCats.concat(ids);
        cb(null, cnt, fullCats, cats, finalCb);
      } else {
        if (cnt > 0) cnt -= 1;
        cb(null, cnt, fullCats, null, finalCb);
      }
    });

  }

  var catSearchCallback = function(err, cnt, fullCats, cats, finalCb) {
    if (err) {
      finalCb(err);
    }
    if (cats) {
      for (var c=0; c<cats.length; c++) {
        cnt += 1;
        Category.getSubCategories(cats[c], cnt, fullCats, catSearchCallback, finalCb);
      }
    } else {
      if (cnt == 0) {
        finalCb(null, fullCats);
      }
    }
  }

  /* start here */
  Category.getAllSubCategories = function(categoryId, cb) {
    Category.findById(categoryId, function(err, cat) {
      if (err) {
        return logger.error(err);
      }
      var fullCats = []; //collection holding ALL ids
      var cnt = 0;  //counter to count how many steps we have done
      if (cat) {
        fullCats.push(categoryId); //the category in question needs to be in the results as well
        Category.getSubCategories(cat, cnt, fullCats, catSearchCallback, function(err, allCats) {
          if (err) {
            cb(err);
          }
          cb(null, allCats);
        });
      } else {
        return categoryId;
      }
    });
  }

2 个答案:

答案 0 :(得分:0)

以下SEEMS正在运行,我在我的系统中对零级,一级和两级层次结构进行了测试,并且它完成了预期的工作(到目前为止......)。

当然可能会有更优雅的解决方案,更有效的解决方案等。 如果你有的话,非常欢迎你分享。 对我来说,暂时,这有效:)

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if touches.count <= 2 {
        for touch: AnyObject in touches {
            // do stuff
            }
        }
    }

答案 1 :(得分:0)

我没有要使用的数据库,也没有完整的代码,例如我不知道Category.find的工作方式。但是正如人们在评论中所说的那样,这是绝对可以使用Promise的代码,而当我们使用它时,为什么不使用async / await。我自己无法运行此代码,因此,请考虑它而不是完整的代码来作为蓝图/算法。所以,这里什么都没有。

用异步/等待方式重写代码:

Category.findAsync = function(condition){
    return new Promise((resolve, reject) => Category.find(
        condition,
        (err, result) => err ? reject(err) : resolve(result)
    ))
}

Category.getSubCategories = async function(parentId){
    return [parentId].concat(Promise.all(
        (await Category.findAsync({where: {parentId}})).map(
            subCategory => Category.getSubCategories(subCategory.id)
        )
    ))
}

运行它:

(async()=>{
    const categoryId = 12345
    console.log(await Category.getSubCategories(categoryId))
})()

因为我不知道find的工作原理,所以我在它周围写了一个名为findAsync的包装,它将回调转换为promise。

*答案结尾*

PS:请所有等待/承诺专家编辑此答案并帮助OP达成可行的解决方案。