Skip to content Skip to sidebar Skip to footer

How Can I Chain Together Groups Of Promises?

I am using the Q javascript promises library and am running in a browser, and I want to figure out how to chain together groups of promises so that each group gets executed sequent

Solution 1:

This can be done by first pre-processing the array of items into groups, then applying the two patterns (not the anti-patterns) provided here under the heading "The Collection Kerfuffle".

The main routine can be coded as a single chain of array methods.

var work_items = [ 'A','B','C','D','E','F','G','H','I' ];
var wait = 3000;

//Async worker functionfunctiongetWorkPromise(item) {
    console.log("Starting " + item);
    var deferred = Q.defer();
    setTimeout(function () {
        var status = "Finished " + item;
        console.log(status);
        deferred.resolve(status);             
    }, wait);
    return deferred.promise;
};

functiondoAsyncStuffInGroups(arr, n) {
    /* 
     * Process original array into groups, then 
     * process the groups in series, 
     * progressing to the next group 
     * only after performing something asynchronous 
     * on all group members in parallel.
     */return arr.map(function(currentValue, i) {
        return (i % n === 0) ? arr.slice(i, i+n) : null;
    }).filter(function(item) {
        return item;
    }).reduce(function(promise, group) {
        return promise.then(function() {
            return Q.all(group.map(function(item) {
                returngetWorkPromise(item);
            }));
        });
    }, Q());
}

doAsyncStuffInGroups(work_items, 2).then(function() {
    console.log("All done");
});

See fiddle. Delay of 3s gives you time to appreciate what's going on. I found 1s too quick.

Solutions like this are elegant and concise but pretty well unreadable. In production code I would provide more comments to help whoever came after me.

For the record:

  • The opening arr.map(...).filter(...) processes arr (non destructively) into an array of arrays, each inner array representing a group of length n (plus terminal remainders).
  • The chained .reduce(...) is an async "serializer" pattern.
  • The nested Q.all(group.map(...)) is an async "parallelizer" pattern.

Solution 2:

The .then function of a promise does not mutate the promise, so when you do:

 p.then(function(){
         // stuff
 });

You do not change the promise p at all, instead, you need to assign it to something:

p = p.then(....)

This is why your queue promise was always resolved, it never changed beyond Q().

In your case, something like changing:

queue.then(Q.all(unit));

Into:

queue = queue.then(function(){ return Q.all(unit); });

Or in ES6 promises and libraries that use their syntax like Bluebird the other answer mentioned:

queue = queue.then(function(){ returnPromise.all(unit); });

Solution 3:

The thing that confused me most is that the async function being chained needs to return a function that returns a promise. Here's an example:

functionsetTimeoutPromise(ms) {
  returnnewPromise(function (resolve) {
    setTimeout(resolve, ms);
  });
}

functionfoo(item, ms) {
  returnfunction() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}

var items = ['one', 'two', 'three'];

functionbar() {
  var chain = Promise.resolve();
  for (var i in items) {
    chain = chain.then(foo(items[i], (items.length - i)*1000));
  }
  return chain.then();
}

bar().then(function () {
  console.log('done');
});

Notice that foo returns a function that returns a promise. foo() does not return a promise directly.

See this Live Demo

Solution 4:

i would suggest you use bluebird, its the best performance promise out there, https://github.com/petkaantonov/bluebird

the example to chain should also be here https://github.com/petkaantonov/bluebird#how-do-long-stack-traces-differ-from-eg-q

Post a Comment for "How Can I Chain Together Groups Of Promises?"