取消承诺链?
我链接了一系列的承诺:
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
请求(请参阅上面的编辑代码) )
来自jquery论坛 :
为了处理潜在的应用程序错误,我会一遍又一遍地执行以下操作:复制代码
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()。
要取消承诺链,您需要抛出错误。 只需看看下面的代码
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 });
有趣的小挑战!
如果不确切知道你正在启动哪个任务,请求或进程以及用户如何中断所述进程,很难推荐任何解决方案来“破解” .then(...)
链而不做一些黑客/技巧触发.catch(...)
拒绝回调。
话虽这么说,看看这个例子是否有所启发。
特别注意makeInterruptablePromise函数及其使用方法:
var bar = $('.progress-bar'); var h3 = $("h3"); var isEscape; function log(msg, replace) { h3[replace ? 'html' : 'append'](msg + "
"); } $(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; }