繁体   English   中英

在Javascript中递归遍历树

[英]Recursively traverse tree in Javascript

这是用Java做的超级简单的任务,但是javascript的异步性质使得这个任务(对我来说)几乎不可能,至少我现在的知识。(我不是想破坏javascript。喜欢这种语言!)。

这是非常基本的。 顶级树在我的mysql数据库中具有null的父级。 很容易找到孩子。 孩子们可以使用线路。 树的深度是可变的。

    private static Set<Tree> getBranches( Tree trunk ) {

    Set<Tree> treeSet = new HashSet<Tree>();

    if ( trunk != null ) {

        if ( trunk.hasLines() ) { //queries if tree has lines.  returns true or false
            treeSet.add( trunk );
        }

        for ( Tree tree : trunk.treeList ) {
            treeSet.addAll( getBranches( tree ) );
        }
    }

    return treeSet;
}

基本上该方法测试树是否有可用的线。 如果是这样,它会将所有这些添加到集合中。 如果没有,它会继续,直到找到线条。

mysql节点库的异步特性将此任务变为地狱。

这就是我现在拥有的

   function hasLines(tree_id, callback) {
        var ret;
        pool.query('SELECT * from pkg_line_tree where tree_id = ?', [tree_id], function (err, rows) {

            if (rows.length > 0) {
                ret = true;
            } else {
                ret = false;
            }
            callback(ret);
        });
    }


     function dig(tree_id, treeArray, callback) {

        pool.query('SELECT * from tree where parent_id = ?', [tree_id], function (err, rows) {

           if (rows) {

              for (var i in rows) {
                 hasLines(rows[i].tree_id, function (t) {

                    if (t) {
                       treeArray.push(rows[i].tree_id);
                    } else {
                       treeArray.concat(dig(rows[i].tree_id, treeArray));
                    }
                 });
              }

              if (callback) {
                 callback(treeArray);
              }

           }
        });

        return treeArray;
     }


     var treeArray = [];
     dig(52, treeArray, function (t) {
        res.json(t);
     });

我真的只需要输出这个根树中可用的所有子节点。

如果这没有意义,请告诉我。 我会尝试重构。 我希望我能得到某种观点。 我讨厌使用像Fibers这样的东西来完成这项任务,但我没有选择。 谢谢。

你必须使用async https://github.com/caolan/async

我修改了你的dig函数以使用async的forEach方法

function dig(tree_id, treeArray, AllDone) {
       pool.query('SELECT * from tree where parent_id = ?', [tree_id], function (err, rows) {
          if (rows) {
            async.forEach(
                rows,
                function(row, callback) {
                    hasLine(row.tree_id, function(t){
                        if (t) {
                            treeArray.push(row.tree_id);
                            callback();
                        }
                        else {
                            dig(row.tree_id, treeArray, callback);
                        }
                    });
                },
                function(err) {
                    if (err) AllDone(err, treeArray);
                    else AllDone(null, treeArray);
                });
            }
          else 
            AllDone(null, treeArray)
        });
}

treeArray = [];
dig(52, treeArray, function(err, t) {  
    res.json(t);  
});

假设rows是一个数组.. forEach遍历每一行并执行hasLine,每次迭代都会在完成后调用callback函数,并且在调用所有callback函数时将调用AllDone 这里棘手的部分是递归,每个递归调用都有一个forEach循环,只有当所有callbacks都完成后才会调用AllDone方法。

但是forEach并行执行,所以订单不能保持

如果您不关心订单,我认为这应该有用。

编辑您可以使用forEachSeries来解决订单问题。

您对dig()使用目前不一致:

// asynchronous with callback
dig(52, treeArray, function (t) {
   res.json(t);
});

// then synchronous with `return`?
treeArray.concat(dig(rows[i].tree_id, treeArray));

此外,最后一行中的concat实际上并没有做太多,因为它不会改变它所调用的数组。 你可能不会真的希望它为dig绕过treeArray而不是定义一个新treeSetgetBranches 所以,如果确实如此,那么每次都会将treeArray附加到自身的末尾。

您仍然可以将concat与多个treeSet一起使用,但您必须存储其return值:

treeSet = treeSet.concat(subSet);

而且,你必须用异步迭代器替换for循环,因为循环不会在继续之前等待异步操作。 如果你想尝试它, async有几个选项。

因此,使用多个treeSetconcatasync.forEachSeries ,您可以尝试:

function dig(tree_id, callback) {
  var treeSet = [];

  hasLines(tree_id, function (yep) {
    if (yep) {
      treeSet.push(tree_id);
    }

    pool.query('SELECT * from tree where parent_id = ?', [tree_id], function (err, rows) {

      function each(row, next) {
        dig(row.tree_id, function (subSet) {
          treeSet = treeSet.concat(subSet);
          next(null);
        });
      }

      function done() {
        callback(treeSet);
      }

      async.forEachSeries(rows, each, done);
    });
  });
}

dig(52, function (treeSet) {
  res.json(treeSet);
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM