0

I have N number of groups of promises and I simply want to run all promises in group 1, and then when all successful, all the promises in group 2, etc up to group N.

My promises are all wrapping traditional async calls so I'm using Q's defer functionality:

createPromise: function (name, duration) {
   return function () {
       console.log('Executing ' + name);

       var deferred = Q.defer();
       setTimeout(function () {
           console.log(name + ' resolved');
           deferred.resolve();
       }, duration);
       return deferred.promise;
   };
},

Here's an example with 2 groups:

    var group1 = [
        this.createPromise('A', 5000), // 5 second delay
        this.createPromise('B', 6000)
    ];

    var group2 = [
        this.createPromise('1', 1000), // 1 second delay
        this.createPromise('2', 1000)
    ];

    var groups = [group1, group2];

I can easily run a single item from group 1 followed by a single item in group 2:

    var q = Q();
    q = q.then(group1[0]);
    q = q.then(group2[0]);

Output:

Executing A
A resolved
Executing 1
1 resolved 

But I simply cannot wrap my head around how to combine all items in group 1 into a single promise.

For example, in this case group1 is not run at all - only group2's first item is executed.

    var q = Q();
    q = q.then(Q.all(group1));
    q = q.then(group2[0]);
nogridbag
  • 3,521
  • 4
  • 38
  • 51
  • I solved this very easily using the RSVP library. I'm sure this is easily doable in Q, but for some reason the Q documentation was a bit more confusing to me. – nogridbag Feb 22 '14 at 17:20

2 Answers2

1

I think you've got the idea right:

q.then(Q.all(group1));

However, there are two flaws in this:

  • Q.all doesn't take an array of functions, but an array of promises. You'll need to do

     Q.all(group1.map(function(create) { return create(); }))
    
  • Q.all does return a promise, yet then does take a function to be called later:

     q = q.then(function(prevGroupResult) {
          return Q.all(…groupN…);
     });
    
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

You should be able to do this with a couple more methods (in the namespace) :

  • runGroup : to run an array of functions in parallel
  • runGroupset : to run an array of groups in sequence.

The functions will be something like this :

runGroup: function (group) {
    //Here we build an array of promises, on which `Q.all` can be applied
    var promises = [];
    for (var i = 0; i < group.length; i++) {
        promises.push(group[i]());
    }
    return Q.all(promises);
},
runGroupset: function (groupset) {
    //Here we build a then chain.
    var p = Q(true);//resolved promise
    for (var i = 0; i < groupset.length; i++) {
        p = p.then((function (i) {
            return function() {
                return myNamespace.runGroup(groupset[i]);
            }
        })(i));
    }
    return p;
}

Use as follows :

var myGroupset = [];
myGroupset.push([
    this.createPromise('A', 5000), // 5 second delay
    this.createPromise('B', 6000)
]);
myGroupset.push([
    this.createPromise('1', 1000), // 1 second delay
    this.createPromise('2', 1000)
]);

myNamespace.runGroupset(myGroupset);

DEMO

Edit

runGroupset modified to read p = p.then(...)inside the for loop.

Edit 2

Further changes above, plus demo.

Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • Your `runGroupSet` does not really work, it just returns `true` – Bergi Feb 22 '14 at 21:43
  • Bergi, I think you are right but for the wrong reason. If `p` wasn't a promise then `p.then()` would throw an error and `runGroupset` would not complete. However, I forgot to reassign to `p` inside the loop. See edit above. – Beetroot-Beetroot Feb 22 '14 at 22:00
  • Thanks all. Both of your answers are correct so I'm not quite sure which to mark as the answer! But as this answer has a runnable demo I have chosen this one. – nogridbag Feb 23 '14 at 00:44
  • Bergi's `Q.all(group1.map(...))` is neat and can be used in place of my `runGroup`. Personally I regard `Array.map` as too new for mainstream internet use. There are too many browsers out there which don't support it. – Beetroot-Beetroot Feb 23 '14 at 03:07