4

这是在 Java 中完成的超级简单的任务,但是 javascript 的异步特性使得这个任务(对我来说)几乎是不可能的,至少就我现在的知识而言。(我不是在尝试 bash 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 这样的东西来完成这项工作,但我别无选择。谢谢。

4

2 回答 2

2

你必须使用异步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完成时都会调用该函数,并AllDone在调用所有callback函数时调用。这里棘手的部分是递归,每个递归调用都会有一个forEach循环,并且AllDone只有在所有callbacks都完成后才会调用该方法。

但是forEach并行执行,因此不保留顺序

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

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

于 2012-09-04T22:43:06.077 回答
2

您的使用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而不是定义一个新的treeSet类似 in getBranches。因此,如果确实如此,它将treeArray每次都附加到自身的末尾。

你仍然可以使用concat多个treeSets,但你必须存储它的return值:

treeSet = treeSet.concat(subSet);

而且,您必须将for循环 this 替换为异步迭代器,因为循环在继续之前不会等待异步操作。如果您愿意尝试,async图书馆对此有一些选择。

因此,对于多个treeSets、concatasync.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);
});
于 2012-09-04T23:16:35.963 回答