When it comes to "canceling a Promise.all()", the idea is to ensure that the promise returned by a Promise.all() does not continue on its success path.
While Promises themselves are not cancelable, there are pattern-based solutions that can achieve a similar effect.
The basic concept behind this approach is fairly straightforward. Essentially, within each batch of promises, you can include a special promise that:
- will be resolved if the current batch is successful
- will be rejected once the next batch is initiated
This sets up a sort of competition between different outcomes.
The challenge lies in seamlessly integrating this "super-aggregation" into the final results.
Here is one possible implementation - although it may not be the most concise, there could be more efficient ways to accomplish this task.
function BatchCanceller() {
// Return a function that takes an array of promises and returns an aggregated promise.
// Use this returned function similarly to how you would use $q.all().
var dfrd;
return function(promises) {
if(dfrd) {
dfrd.reject(new Error('cancelled')); // reject previous batch
}
dfrd = $q.defer();
// Prepare for all promises to resolve `dfrd` if successful.
$q.all(promises).then(dfrd.resolve);
// Include `dfrd` in a super-aggregation of promises.
return $q.all(promises.concat(dfrd.promise)).then(function(results) {
// If the aggregated promises succeed, remove the last result (from `dfrd`)
return results.splice(0, results.length-1);
});
};
}
var batchCanceller = new BatchCanceller();
var promises = [/* whatever */];
batchCanceller(promises).then(function(results) {
console.log(results);
}).catch(function(error) {
console.log(error); // will display "cancelled" if another batchCanceller(promises) is called before the previous one resolves
});
In practical applications, it might be more suitable to implement BatchCanceller()
as an Angular factory.