Reputation: 55779
A user is able to make asynchronous calls by entering a value in a UI.
When the user changes the value in the UI, another async call is made - possibly before the callback supplied to the promise returned from the async call has been invoked.
The async API being used returns a Q based promise.
How can I cancel the original call gracefully, ensuring that even if the system returns with a value for the first call, the .then
part of the promise is not invoked with that value (but that it is eventually invoked when the second async call completes)?
Upvotes: 1
Views: 377
Reputation: 42520
Absent some cancellation API, each async call will run to completion, but if all you're looking for is canceling the .then() functions, then that's doable. The most straight-forward way is a counter:
var counter = 0;
function onClick() {
counter++;
doAsyncCall().then(function(result) {
if (!--counter) {
myFunc(result);
}
});
}
But you asked for graceful, so maybe a more reusable construct would be something like this:
var idle;
function onClick(){
idle = Overtake(idle, doAsyncCall());
idle.then(myFunc).then(myOtherFunc);
}
which could be implemented like this:
function Overtaker(prior, callp) {
if (prior) {
prior.cancel();
}
var p;
p = new Promise(function(resolve, reject) {
callp.then(function(value) { return p && resolve(value); },
function(reason) { return p && reject(reason); });
});
this.cancel = function() { p = null; }
this.then = function(onFulfilled, onRejected) {
return p.then(onFulfilled, onRejected);
}
}
function Overtake(prior, p) {
return new Overtaker(prior, p);
}
I'm using ES6 promises, but Q promises seem similar, so hopefully this works there as well.
Upvotes: 0
Reputation: 35106
Back in the day I had a case like this (node.js) where I was either doing a web or a db request. I had a timeout object, which I think was cancellable (sry, don't remember the details) and had promises on both of them. So if the webpage returned first, I'd cancel the timeout and return the html. And if the timeout happened first, I updated a "timedout" field in some JSON to yes, so that if the web call ever returned, it would know just to die. It was a little mind-blowing, because with these promises, I could enter the function once, and actually return twice!
Hope that helps
-Tom
Upvotes: 1