Отмена обещаний
Пользователь может выполнять асинхронные вызовы, вводя значение в пользовательском интерфейсе.
Когда пользователь изменяет значение в пользовательском интерфейсе, выполняется еще один асинхронный вызов - возможно, до вызова обратного вызова, предоставленного обещанию, возвращенному из асинхронного вызова.
Используемый асинхронный API возвращает обещание на основе Q.
Как можно изящно отменить исходный вызов, гарантируя, что даже если система вернет значение первого вызова, .then
часть обещания не вызывается с этим значением (но что оно в конечном итоге вызывается после завершения второго асинхронного вызова)?
2 ответа
В тот день у меня был такой случай (node.js), когда я делал веб-запрос или отправлял запрос в db. У меня был объект тайм-аута, который, я думаю, был отменен (извините, не помню деталей) и имел обещания на обоих из них. Так что, если веб-страница вернулась первой, я бы отменил тайм-аут и вернул HTML. И если сначала произошел тайм-аут, я изменил поле "тайм-аут" в некотором JSON на yes, так что если веб-вызов когда-либо вернется, он узнает только о смерти. Это было немного ошеломляюще, потому что с этими обещаниями я мог войти в функцию один раз и фактически вернуться дважды!
надеюсь, это поможет
-Том
В отсутствие некоторого API отмены каждый асинхронный вызов будет выполнен до конца, но если все, что вам нужно, это отменить функции.then(), то это выполнимо. Самый простой способ - счетчик:
var counter = 0;
function onClick() {
counter++;
doAsyncCall().then(function(result) {
if (!--counter) {
myFunc(result);
}
});
}
Но вы попросили изящную, так что, возможно, более многократно используемая конструкция будет выглядеть примерно так:
var idle;
function onClick(){
idle = Overtake(idle, doAsyncCall());
idle.then(myFunc).then(myOtherFunc);
}
который может быть реализован так:
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);
}
Я использую обещания ES6, но обещания Q кажутся похожими, так что, надеюсь, там это тоже работает.