这是用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这样的东西来完成这项任务,但我没有选择。感谢。
答案 0 :(得分:2)
你必须使用异步https://github.com/caolan/async
我已修改您的挖掘功能以使用async&#39; 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
时调用{1}}函数被调用。这里棘手的部分是递归,每个递归调用将有一个forEach
循环,只有当所有AllDone
完成时才会调用callbacks
方法。
然而forEach
并行执行,因此订单不会被保留
如果您不关心订单,我认为这应该有用。
修改:您可以使用forEachSeries
解决订单问题。
答案 1 :(得分: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
中那样定义新的getBranches
。所以,如果确实如此,那么每次都会将treeArray
附加到自身的末尾。
您仍然可以将concat
用于多个treeSet
,但您必须存储其return
值:
treeSet = treeSet.concat(subSet);
并且,你必须用异步迭代器替换for
循环,因为循环不会在继续之前等待异步操作。 async
library有一些选择,如果你想尝试它。
因此,对于多个treeSet
,concat
和async.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);
});