【发布时间】:2016-04-14 13:09:15
【问题描述】:
我有一个要使用 Promises 遍历的树形结构,但我还没有找到正确的代码模式。
假设我们得到了节点名称,并且将节点名称转换为节点的行为是一个异步过程(例如,涉及 Web 访问)。还假设每个节点都包含一个(可能为空的)子名称列表:
function getNodeAsync(node_name) {
// returns a Promise that produces a node
}
function childrenNamesOf(node) {
// returns a list of child node names
}
我想用这个签名的方法结束:
function walkTree(root_name, visit_fn) {
// call visit_fn(root_node), then call walkTree() on each of the
// childrenNamesOf(root_node), returning a Promise that is fulfilled
// after the root_node and all of its children have been visited.
}
它返回一个在根节点及其所有子节点都被访问后实现的 Promise,因此它可能被如下调用:
walkTree("grandpa", function(node) { console.log("visiting " + node.name); })
.then(function(nodes) { console.log("found " + nodes.length + " nodes.")});
更新
I've create a gist that shows my first attempt。我对 walkTree() 的(有点错误的)实现是:
function walkTree(node_name, visit_fn) {
return getNodeAsync(node_name)
.then(function(node) {
visit_fn(node);
var child_names = childrenNamesOf(node);
var promises = child_names.map(function(child_name) {
walkTree(child_name, visit_fn);
});
return Promise.all(promises);
});
};
这会以正确的顺序访问节点,但最外层的 Promise 在所有子节点都被访问之前解析。 See the gist for full details.
正如@MinusFour 指出的那样,使用这种技术来展平节点列表是毫无意义的。事实上,我真的只想在所有节点都被访问后触发最终的承诺,所以一个更现实的用例是:
walkTree("grandpa", function(node) { console.log("visiting " + node.name); })
.then(function() { console.log("finished walking the tree")});
【问题讨论】:
-
你的想法是好的和直截了当的。
walkTree方法可以批量处理从访问每个节点返回的承诺,然后当所有这些承诺都已实现时,它会使用承诺数组或您决定它应该解决的任何内容来解决(这样您就可以访问长度,不确定您还想用它做什么)。这将做类似于RSVP.all可能做的事情(在等待一批承诺解决或如果其中一个拒绝时拒绝承诺)。 -
您的要点正是正确的方法。唯一的问题是您在
map回调中错过了return声明!
标签: javascript promise