我将一系列承诺链接起来:
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();
})
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
请求(请参见上面编辑过的代码)。userRequestedCancel
设置为true
时,也取消上一个请求。 - Adam JenkinscurrentReq
)为真,则评估&&
后面的内容 - 这与说if(currentReq) { currentReq.abort(); }
是相同的。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators - Adam Jenkinsfunction 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
});
有趣的小挑战!
如果不知道你正在启动哪个任务、请求或进程,以及用户如何中断该进程,那么很难推荐任何解决方案来“打破”.then(...)
链,而不进行一些会触发.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)。
不确定它是否符合您的需求,但对于任何试图通过某些外部/异步因素打破Promises的人可能会有用。
var state = { running: true }
,然后您可以根据需要测试if (state.running) { return this.getMoreData() }
。 - tadman