Javascript NodeJS中的递归异步循环

Javascript NodeJS中的递归异步循环,javascript,node.js,recursion,promise,Javascript,Node.js,Recursion,Promise,我正在尝试执行一个递归异步循环,以从nodejs中的第三方库跟踪特定对象的所有子对象 以下是伪代码: var tracer = function(nodes){ var promises []; nodes.forEach(function(node){ // trace returns a promise ... var promise = builder.trace(node) promises.push(promise); promise.th

我正在尝试执行一个递归异步循环,以从nodejs中的第三方库跟踪特定对象的所有子对象

以下是伪代码:

var tracer = function(nodes){
  var promises [];

  nodes.forEach(function(node){

    // trace returns a promise ...
    var promise = builder.trace(node)
    promises.push(promise);

    promise.then(function(tree){

      // if we had children, get those
      if(tree.children.length){
        promises.push.apply(promises, tracer(tree.children));
      }
    });   

  });

  return promises;
};

RSVP.all(tracer(myArr)).then(function(allTrees){ ... });

但是我无法确定如何正确解析它们,并在一个数组中返回结果。

您不能在延迟回调中推送数组上的递归承诺。相反,您需要立即推出一个表示递归结果的承诺(用延迟产生的承诺解决)。幸运的是,你甚至从那次
电话中得到了确切的答案

此外,我会将
每个
替换为
映射
,并在函数内部立即执行
RSVP.all
,以避免调用方处理该问题

function tracer(nodes){
  var promises = nodes.map(function(node){
    // trace returns a promise ...
    var promise = builder.trace(node)
    var recusivePromise = promise.then(function(tree){
      // if we had children, get those
      if (tree.children.length)
        return tracer(tree.children));
      else
        return node;// the leaf node itself
    });
    return recusivePromise; // which will resolve with the `tracer(…)` result
                            // or the leaf
  });
  return RSVP.all(promises);
}

tracer(myArr).then(function(allTrees){ … });

您不能在延迟回调中推送数组上的递归承诺。相反,您需要立即推出一个表示递归结果的承诺(用延迟产生的承诺解决)。幸运的是,你甚至从那次
电话中得到了确切的答案

此外,我会将
每个
替换为
映射
,并在函数内部立即执行
RSVP.all
,以避免调用方处理该问题

function tracer(nodes){
  var promises = nodes.map(function(node){
    // trace returns a promise ...
    var promise = builder.trace(node)
    var recusivePromise = promise.then(function(tree){
      // if we had children, get those
      if (tree.children.length)
        return tracer(tree.children));
      else
        return node;// the leaf node itself
    });
    return recusivePromise; // which will resolve with the `tracer(…)` result
                            // or the leaf
  });
  return RSVP.all(promises);
}

tracer(myArr).then(function(allTrees){ … });

我最终选择了一种计数器类型的方法

var traceDeps = function(parents, cb){
  var count = 0, 
    trees = [], 
    trace = function(nodes){
      nodes.forEach(function(node){
        count++;
        builder.trace(node).then(function(tree){
          trees.push(tree);

          if(tree.children.length){
            trace(tree.children);
          }

          count--;
          if (count === 0) cb(trees);
        });
      });
    };

  trace(parents);
};

traceDeps(myArr, function(trees){ ... });

我最终选择了一种计数器类型的方法

var traceDeps = function(parents, cb){
  var count = 0, 
    trees = [], 
    trace = function(nodes){
      nodes.forEach(function(node){
        count++;
        builder.trace(node).then(function(tree){
          trees.push(tree);

          if(tree.children.length){
            trace(tree.children);
          }

          count--;
          if (count === 0) cb(trees);
        });
      });
    };

  trace(parents);
};

traceDeps(myArr, function(trees){ ... });

tracer(myArr)
怎么会有
?在此代码中,您没有返回使用
的承诺。那么
tracer(myArr)
怎么会有
。那么
?在这段代码中,您没有返回使用
的承诺。那么
开启。为什么这么复杂?当您可以使用承诺时,无需使用回调和计数器。此外,这种方法会忽略错误。如果任何
trace()
承诺被拒绝,您不会注意到(而是无限期地等待从未调用过的回调),此解决方案不如Bergi,并且会忽略错误。你应该考虑用他的代替。Ya,我同意。谢谢你的帖子@Bergi为什么这么复杂?当您可以使用承诺时,无需使用回调和计数器。此外,这种方法会忽略错误。如果任何
trace()
承诺被拒绝,您不会注意到(而是无限期地等待从未调用过的回调),此解决方案不如Bergi,并且会忽略错误。你应该考虑用他的代替。Ya,我同意。感谢@BergiNote:这篇文章返回列表列表与平面数组的比较。@amcdnl:是的,它应该与树结构相匹配。如果您想要一个平面数组,请使每个
recursivePromise
使用一个数组进行解析(通过在单例数组中返回leaf),并在
之后添加一个
concat
步骤。all()
@DanKanze:这是基本函数编程:-)注意:这将返回列表列表与平面数组。@amcdnl:是的,它应该与树结构匹配。如果您想要一个平面数组,请使每个
recursivePromise
用一个数组解析(通过在单例数组中返回leaf),并在
之后添加一个
concat
步骤