我連鎖一系列承諾:取消承諾鏈?
this.getData.then(this.getMoreData).then(this.getEvenMoreData);
在一些點,用戶可以決定取消該請求,並要求別的東西。
如何取消鏈條的傳播?
我連鎖一系列承諾:取消承諾鏈?
this.getData.then(this.getMoreData).then(this.getEvenMoreData);
在一些點,用戶可以決定取消該請求,並要求別的東西。
如何取消鏈條的傳播?
你不得不檢查狀態(你是否應該取消或不)每個鏈接的方法中:
var userRequestedCancel = false;
this
.getData()
.then(function() {
if(userRequestedCancel) {
return Promise.reject('user cancelled');
}
return getMoreData();
})
.then(function() {
if(userRequestedCancel) {
return Promise.reject('user cancelled');
}
return getEvenMoreData();
})
或許稍微更優雅的方式(編輯通過上下文和參數到callback
方法)
var currentReq = false;
var userRequestedCancel = false;
var shouldContinue = function(cb,args) {
if(userRequestedCancel) {
return Promise.reject('user cancelled');
}
currentReq = cb.apply(this,args);
return currentReq;
}
var onCancel = function() {
userRequestedCancel = true;
currentReq && currentReq.abort();
}
this
.getData()
.then(function() {
return shouldContinue(getMoreData,arguments);
})
.then(function() {
return shouldContinue(getEvenMoreData,arguments);
})
如果您需要取消當前請求的很好,那是一種平凡,設置當前ajax
請求是一個全局變量,和什麼如果有事件將userRequestedCancel
標誌設置爲true,那麼也取消ajax
請求(請參閱上面編輯的代碼)
Asuming getData()是一些Ajax請求,當沒有收到答案時,該請求應該中止。 –
@NickRussler - 沒有任何概念上更困難。請參閱編輯後的代碼 - 保留對當前ajax請求的引用,並且只要將'userRequestedCancel'設置爲'true' - 也取消上次請求。 – Adam
是的,剛剛提到它,因爲op說「該網站獲得**很多數據** [...]」 –
爲了應對潛在的應用程序錯誤,我做了以下一遍又一遍: 複製代碼
var deferred = $.Deferred().done(stuff_to_do).fail(handle_application_error);
$.post(url, params, function(data) { special_error_check(data, deferred) }, 'json');
的special_error_check()認爲,如果JSON數據包含錯誤 消息。如果是這樣,它調用deferred.reject()。如果沒有錯誤,則調用deferred.resolve()。
這個不回答問題 – panthro
爲什麼不能?你真的讀過我的回答嗎? –
爲了取消承諾鏈,您需要引發錯誤。只需看看下面的代碼
function CancelError() {
this.message = 'Cancelled';
}
obj
.then(function() {
throw new CancelError();
})
.catch(function(err) {
if (err instanceof CancelError) {
// Promise got cancelled
}
throw err; // throw the other mistakes
});
我該如何從鏈外引發錯誤?如果用戶啓動一個新鏈,我需要取消當前鏈。 – panthro
有趣的小挑戰!
不知道你正在啓動哪個任務,請求或過程,以及用戶如何中斷上述過程,很難推薦任何解決方案來「破壞」鏈,而不做一些破解/誘騙, .catch(...)
拒絕回撥。
話雖如此,看看這個例子是否有一點亮光。
要特別注意makeInterruptablePromise功能和如何使用它:
var bar = $('.progress-bar');
var h3 = $("h3");
var isEscape;
function log(msg, replace) {
h3[replace ? 'html' : 'append'](msg + "<br/>");
}
$(document).keydown(e => {
switch(e.keyCode) {
case 27: //ESCAPE
return isEscape = true;
case 32: //SPACE
return runDemo();
}
});
function makeInterruptablePromise(cbStatus) {
return new Promise((resolve, reject) => {
function loop() {
switch(cbStatus()) {
case 1: return resolve();
case -1: return reject();
default: requestAnimationFrame(loop);
}
}
//Don't forget to start the loop!
loop();
})
}
function runDemo() {
log("Wait for it... (ESC to interrupt, SPACE to replay)", true);
isEscape = false;
var timeToComplete = 2000;
var timeStart = Date.now();
function updateBar() {
var timeDiff = Date.now() - timeStart;
var timePercent = timeDiff/timeToComplete;
TweenMax.set(bar, {scaleX: 1 - timePercent});
return timePercent > 1;
}
makeInterruptablePromise(() => {
if(isEscape) return -1;
if(updateBar()) return 1;
return 0;
})
.then(() => log("Inside *then* chain."))
.catch(() => log("Skipped *then* chain!"))
}
runDemo(); //Run first time.
body {
background-color: #123456;
color: #fff;
}
.progress-bar {
display: block;
width: 200px;
height: 10px;
background-color: #88f;
transform-origin: top left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenMax.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="progress-bar"></div>
<h3></h3>
這本質歸結爲,是我傳遞一個回調makeInterruptablePromise
到「監控「有3種可能的狀態。
requestAnimationFrame(...)
方法。 (主要是setTimeout(...)
已校準,以觸發每個屏幕 刷新)。現在,影響到這些狀態隨時間的變化如何,我證明了這一點,通過使用ESCAPE
作爲中斷狀態(-1)和2秒運行一次的計時器。一旦完成,定時器返回狀態(1)。
不確定它可以滿足您的需求,但可能對任何試圖通過某些外部/異步因素破壞Promise的人有用。
你是什麼意思「用戶」?這是一段儘快執行的代碼,您如何在此添加用戶干預? – tadman
該網站獲取了大量的數據。如果用戶請求其他數據,我想停止獲取當前的一組數據並輸出它。 – panthro
那該怎麼玩呢?是否有這個請求的狀態對象表明它被取消,比如'var state = {running:true}',然後你可以根據需要測試if(state.running){return this.getMoreData()}。 – tadman