Skip to content

Instantly share code, notes, and snippets.

@mzipay
Last active August 29, 2015 14:18
Show Gist options
  • Save mzipay/78ce922b717d60899953 to your computer and use it in GitHub Desktop.
Save mzipay/78ce922b717d60899953 to your computer and use it in GitHub Desktop.
INDEPENDENT parallel promises with AngularJS $q.all
/*
* @license CC0 1.0 (http://creativecommons.org/publicdomain/zero/1.0/)
*
* Angular's $q.all works great for cases where a rejection of any one promise
* SHOULD cause all parallel promises to be rejected... but it's not so great
* when you've got a number of promises that need to run in parallel and you
* don't want a single rejection to reject the entire $q.all promise.
* (One example: think aggregating data from multiple APIs.)
*
* This gist shows one way to "partially resolve" parallel processes when at
* least one $q.all promise is rejected. To keep the code concise and focused,
* just imagine that itGetsResolved.query() and itGetsRejected.query() return
* $http.get promises that do what they suggest (get resolved and rejected,
* respectively).
*/
var example = angular.module('independent-parallel-promises', [
'it-gets-resolved-service',
'it-gets-rejected-service'
]);
example.service('aggregator', ['$q', '$log', function($q, $log) {
/** @private */
function keepResponse(response) {
return response;
}
/** @private */
function logAndKeepError(e) {
$log.error('rejected query', e.config.url);
return e;
}
this.aggregate = function() {
return $q(function(resolve, reject) {
$q.all([
itGetsResolved.query().then(keepResponse).catch(logAndKeepError),
itGetsRejected.query().then(keepResponse).catch(logAndKeepError)
])
.then(function(responses) {
// it's up to YOU whether to resolve or reject the aggregate promise!
resolve({
'it-gets-resolved-response': responses[0], // array of whatever
'it-gets-rejected-response': responses[1] // an Error object
});
});
// NOTE: q.all.catch won't be invoked in this scenario
});
};
}]);
/**
* @license CC0 1.0 (http://creativecommons.org/publicdomain/zero/1.0/)
*
* An alternative implementation of the 'aggregator' service that simply
* uses an empty array instead of an Error object when a promise is rejected,
* and resolves with a concatenated array of all responses.
*/
example.service('aggregator', ['$q', '$log', function($q, $log) {
/** @private */
function keepResponse(response) {
return response;
}
/** @private */
function logAndIgnoreError(e) {
$log.error('ignoring rejected query', e.config.url);
return [];
}
this.aggregate = function() {
return $q(function(resolve, reject) {
$q.all([
itGetsResolved.query().then(keepResponse).catch(logAndIgnoreError),
itGetsRejected.query().then(keepResponse).catch(logAndIgnoreError)
])
.then(function(responses) {
resolve(
responses[0] // array of whatever
.concat(responses[1]) // empty array
);
});
});
};
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment