Concurrent Promises with Q

What if you want to execute multiple promises concurrently (using Q)?

Q(Q(1), Q(2), Q(3))
    .then(function (one, two, three) { 
        console.log(one);
        console.log(two);
        console.log(three);
    }, function (ex) {
        console.error(ex.stack);
    });
// 1

You can’t simply wrap them all with a call to Q. Only the first promise will be handled as expected. It’s as if the other 2 are just ignored.

Enter Q.all. Instead of passing your promise functions as individual arguments to Q, pass them as an array to Q.all. (Careful not to forget the array!)

Q.all([Q(1), Q(2), Q(3)])
    .then(function (one, two, three) {
        console.log(one);
        console.log(two);
        console.log(three);
    }, function (ex) {
        console.error(ex.stack);
    });
// [1,2,3]

Now all three promises are handled as expected; however, their return values are passed back as an array. That’s easy enough to work with.

Q.all([Q(1), Q(2), Q(3)])
    .then(function (one, two, three) {
        console.log(one[0]);
        console.log(one[1]);
        console.log(one[2]);
    }, function (ex) {
        console.error(ex.stack);
    });
// 1
// 2
// 3

Q offers a way to get the return values back as parameters instead of an array: use spread instead of then. The return values become the parameters of the function you pass to spread, and like the array above, the order of the parameters corresponds to the order you call the respective promise functions.

Q.all([Q(1), Q(2), Q(3)])
    .spread(function (one, two, three) {
        console.log(one);
        console.log(two);
        console.log(three);
    }, function (ex) {
        console.error(ex.stack);
    });
// 1
// 2
// 3

What happens when one or more of the promise functions is rejected or throws an error?

Q.all([Q(1), Q.reject('rejected!'), Q.reject('fail!')])
    .spread(function (one, two, three) {
        console.log(one);
        console.log(two);
        console.log(three);
    }, function (reason, otherReason) {
        console.log(reason);
        console.log(otherReason);
    });
// rejected!
// undefined

The subsequent onRejected function is called with the rejection reason of the first rejected promise.

Comments, questions and feedback welcome.