If I understood correctly (finally), this is what you are trying to achieve:
- Input:
- a list of promises
- a callback to be called when all promises have been resolved
- a callback to be called each time any of the promises gets rejected
- Behaviour:
- You want parallel execution (not sequential).
- You want all promises to be either resolved or rejected (i.e. even if one promise gets rejected, the rest should continue as usual).
- You want the "final" callback to be called exactly once (receiving an array of results - regardless if the respective deferred was resolved or rejected).
$q.all
should be "augmented" to suit your needs, because by default:
- It gets immediatelly rejected as soon as any of the promises in the list gets rejected.
- In case of rejection it returns only the rejection reason and not a list of results.
Here is a possible implementation:
function asyncCall(listOfPromises, onErrorCallback, finalCallback) {
listOfPromises = listOfPromises || [];
onErrorCallback = onErrorCallback || angular.noop;
finalCallback = finalCallback || angular.noop;
// Create a new list of promises that can "recover" from rejection
var newListOfPromises = listOfPromises.map(function (promise) {
return promise.catch(function (reason) {
// First call the `onErrroCallback`
onErrorCallback(reason);
// Change the returned value to indicate that it was rejected
// Based on the type of `reason` you might need to change this
// (e.g. if `reason` is an object, add a `rejected` property)
return 'rejected:' + reason;
});
});
// Finally, we create a "collective" promise that calls `finalCallback` when resolved.
// Thanks to our modifications, it will never get rejected !
$q.all(newListOfPromises).then(finalCallback);
}
See, also, this short demo.