karthikeayan
karthikeayan

Reputation: 5000

NodeJS recursive call inside for loop, how to know when all calls are done?

enter image description here

I am writing a recursive function inside for loop like below:

var output = [];
function myFunc(myValue, callback) {
  myAnotherFunc(myValue, function(result){
    for (var i=0; i < result.myKey.length; i++){
      if(result.myKey[i].name === 'something'){
        myFunc(result.myKey[i].recurseValue, function(recursiveResult){
          //some recursive stuff
          output.push(recursiveResult.someValue)
        });
      }
    }
  });
}

And initiating the recursive function like below:

myFunc(initialValue, function(result){
  //some stuff
});

Its working fine, but how do I know when my recursive flow ends so that I can do something else from the final output?

Upvotes: 0

Views: 377

Answers (2)

AP.
AP.

Reputation: 8921

You can use Promises™! It's basically a way to defer a callback till after an Asynchronous flow is completed: Example:

// Instead of passing your normal callback, we'll tell the
// function to use resolve(results) to pass your results to the 
// next code block so it can do something after all your recursions are completed
const someTask = new Promise(resolve => myFunc(initialValue, resolve))

someTask.then(result => {
  /* Do Something with the results at the end of aformentioned callback hell :D */
})

PS. You also have to modify your original function signature to:

function myFunc(myValue, callback) {
  myAnotherFunc(myValue, function(result){
    const cbks = [] //Store the async resuls of all myFunc() executions
    for (i=0; i < result.myKey.length; i++){
      if(results[i] === 'something'){
        cbks.push(new Promise(res => myFunc(result[i].recurseValue, res)))
      }
    }
    //Run all async myFunc() and return the results in an array
    Promise.all(cbks).then(callback)
  });
}

Upvotes: 2

Jared Smith
Jared Smith

Reputation: 21926

function myFunc(resolve) {
  var rec = function(myVal, cb) {
    myOther(recurseValue, function(result) {
      var hasName = result[myKey].filter(function(obj) {
        return obj.name === 'something';
      })[0];
      if (hasName) {
        rec(hasName[recurseValue], function(recResult) {
          // other recursive stuff
        });
      } else {
        resolve(?); // whatever the final value should be
      }
    });
  };
  return rec;
}

function recurseAsync(f, initial) {
  return new Promise(function(resolve, reject) {
    f(resolve)(initial);
  });
}

Couple notes.

The recurseAsync function takes a function that takes a resolution callback and returns a recursive function that calls that callback when finished to resolve the promise. myFunc has been altered to fit that format.

I used array filtering rather than a for loop and shortened some names. Also if you are using a variable for object access use [] instead of .. To use the final value when all of this is finished you can call .then on the promise.

// whatever initial value 'foo' should be
var finished = recurseAsync(myFunc, foo);
finished.then(function(finalValue) {
  // do something with the final result of all the recursion
});

Upvotes: 0

Related Questions