Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chaining nested promises in a loop

I am kind of new to promises and are stuck on the following exercise.

I have an array of values and I want to execute an async call on each one. In the callback, I want to execute another call on the outcome of the first call.

Basically, my frustration is in the following: The order of execution should be '1x2x3x' but the order is '123xxx'

In other words, the loop is already going to the next iteration when the sub/nested promise of the first promise is not fullfilled yet..

var values = ["1", "2", "3"];

function do(val) {
  var deferred = Q.defer();


  asyncCall(val)
  .then( function( response ) {
    console.log(val); 
    asyncCall(response)
    .then( function ( response ) {
      console.log('x');
      deferred.resolve(true)
    });
  });

  return deferred.promise;
}

var result = do(values[0]);

values.forEach( function(f) {
  result = result.then(do(f));
}

There is probably an easy solution but I'm stuck on it.

like image 211
strai Avatar asked May 20 '14 20:05

strai


1 Answers

You don't need the deferred, that's the deferred anti pattern you have there since promises chain.

Also, you have to return a promise from a .then handler if you want it to wait for it to resolve.

You can simply use a for loop:

function do(val) {

  var q = Q();
  for(var i = 0; i < val; i++){
    q = q.then(asyncCall.bind(null,i))
         .then(console.log.bind(console))
         .then(console.log.bind(console,"x"));
  }

  return q; // in case you want to chain
}

fiddle.

Note: Bind just fixates the value for the function call. In this case since the first param (the this value) is null it acts like function(fn,arg){ return function(arg){ return fn(arg); }} that is, it translates a function call to a "partial application" - for more info see the MDN docs.

like image 199
Benjamin Gruenbaum Avatar answered Nov 02 '22 10:11

Benjamin Gruenbaum