Javascript 在树遍历完成回调后执行函数

Javascript 在树遍历完成回调后执行函数,javascript,node.js,mongoose,callback,tree,Javascript,Node.js,Mongoose,Callback,Tree,我有一个简单的树,其中ID是Mongo集合的关键。我正在使用一个名为的节点库。当我遍历树的每个节点时,我试图查找名称(使用mongoose)并简单地将其附加到当前节点。如果我不执行回调来查找节点名,而只是使用某个固定值,则会得到我期望的值。让我用代码来说明: 这是我的树: { "categoryTree": [ { "categoryId": "1", "children": [ { "categoryId": "2",

我有一个简单的树,其中ID是Mongo集合的关键。我正在使用一个名为的节点库。当我遍历树的每个节点时,我试图查找名称(使用mongoose)并简单地将其附加到当前节点。如果我不执行回调来查找节点名,而只是使用某个固定值,则会得到我期望的值。让我用代码来说明:

这是我的树:

{
  "categoryTree": [
    {
      "categoryId": "1",
      "children": [
        {
          "categoryId": "2",
          "children": [
            {
              "categoryId": "3",
              "children": []
            },
            {
              "categoryId": "4",
              "children": []
            }
          ]
        },
        {
          "categoryId": "5",
          "children": []
        },
        {
          "categoryId": "6",
          "children": []
        }
      ]
    },
    {
      "categoryId": "7",
      "children": [
        {
          "categoryId": "8",
          "children": []
        }
      ]
    }
  ]
}
下面是我想要的代码:

catTree.categoryTree.forEach(function(node){
    var counter = 0;
    tree.walkTree(node, 'children', function(obj){
        obj.name = counter++;
    });
});
//This tree has the names (as the counter above) in it as I expect
console.log(JSON.stringify(catTree));
但是,只要我抛出mongoose回调来获取类别名称,打印的类别树就不再有名称

catTree.categoryTree.forEach(function(node){
    tree.walkTree(node, 'children', function(obj){
        //Cat is a mongoose model defined elsewhere
        Cat.findById(obj.categoryId, {_id:0,name:1}).exec(function(err, value){
            obj.name = value.name;
        });
    });
});
//This tree has NO names :(
console.log(JSON.stringify(catTree));
我知道这是一个时间问题,但我不知道如何解决它。我看过几篇这样的文章,它们建议跟踪回调并在调用完所有回调后才继续。我不知道如何将该模式应用到我的案例中,因为我正在遍历一棵树,而不仅仅是迭代一个平面列表。我开始认为我的问题可能是我在使用treewalker库,而不是在访问每个节点后编写自己的回调算法


我真的很感谢你的帮助

数据库调用是异步的。这意味着它们将在未来的一段时间内完成,
.forEach()
迭代完成后很久。如果您的数据库可以处理一次抛出的整个查询树(基本上并行运行所有这些查询),那么您可以做如下简单的事情:

let cntr = 0;
catTree.categoryTree.forEach(function(node){
    tree.walkTree(node, 'children', function(obj){
        //Cat is a mongoose model defined elsewhere
        ++cntr;
        Cat.findById(obj.categoryId, {_id:0,name:1}).exec(function(err, value){
            --cntr;
            if (!err) {
                obj.name = value.name;
            }
            // see if all requests are done
            if (cntr === 0) {
                console.log(JSON.stringify(catTree));
            }
        });
    });
});
每当您试图协调多个异步操作时,使用承诺(因为这正是它们的构建目的)通常是有意义的,mongoose为查询内置了承诺。在这里,您将从每个查询中收集一个承诺到一个数组中,然后
promise.all()
告诉您何时完成所有查询

let promises = [];
catTree.categoryTree.forEach(function(node){
    tree.walkTree(node, 'children', function(obj){
        //Cat is a mongoose model defined elsewhere
        let p = Cat.findById(obj.categoryId, {_id:0,name:1}).exec().then(function(value) {
            obj.name = value.name;
        });
        promises.push(p);
    });
});

Promise.all(promises).then(function() {
    console.log(JSON.stringify(catTree));
}).catch(function(err) {
    // error
    console.log(err);
});

看看async.jsp,这太棒了!谢谢你的回答和解释。如果我能给你买杯啤酒,我会的。