amcdnl
amcdnl

Reputation: 8638

Recursive Async Looping in NodeJS

I'm trying to do a recursive async loop to trace all the children of a particular object from a third-party lib in nodejs.

Heres the pseudo code:

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){ ... });

but I can't put my finger on how to get them all to resolve correctly and returns the results in one array.

Upvotes: 0

Views: 1068

Answers (2)

Bergi
Bergi

Reputation: 664195

You must not push the recursive promises on the array in the delayed callback. Instead, you'll need to push a promise that represents the recursive results (resolves with those delayed produced promises) right away. Luckily, you even get exactly that back from that then call.

Additionally, I would swap out the each for a map, and do RSVP.all immediately inside the function, for not expecting the caller to deal with that.

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){ … });

Upvotes: 4

amcdnl
amcdnl

Reputation: 8638

I ended up going with a counter type approach ...

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){ ... });

Upvotes: 0

Related Questions