2015-06-22 57 views
1

我連鎖一系列承諾:取消承諾鏈?

this.getData.then(this.getMoreData).then(this.getEvenMoreData); 

在一些點,用戶可以決定取消該請求,並要求別的東西。

如何取消鏈條的傳播?

+1

你是什麼意思「用戶」?這是一段儘快執行的代碼,您如何在此添加用戶干預? – tadman

+0

該網站獲取了大量的數據。如果用戶請求其他數據,我想停止獲取當前的一組數據並輸出它。 – panthro

+0

那該怎麼玩呢?是否有這個請求的狀態對象表明它被取消,比如'var state = {running:true}',然後你可以根據需要測試if(state.running){return this.getMoreData()}。 – tadman

回答

1

你不得不檢查狀態(你是否應該取消或不)每個鏈接的方法中:

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請求(請參閱上面編輯的代碼)

+0

Asuming getData()是一些Ajax請求,當沒有收到答案時,該請求應該中止。 –

+0

@NickRussler - 沒有任何概念上更困難。請參閱編輯後的代碼 - 保留對當前ajax請求的引用,並且只要將'userRequestedCancel'設置爲'true' - 也取消上次請求。 – Adam

+1

是的,剛剛提到它,因爲op說「該網站獲得**很多數據** [...]」 –

0

jquery forum

爲了應對潛在的應用程序錯誤,我做了以下一遍又一遍: 複製代碼

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()。

+0

這個不回答問題 – panthro

+0

爲什麼不能?你真的讀過我的回答嗎? –

0

爲了取消承諾鏈,您需要引發錯誤。只需看看下面的代碼

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 
    }); 
+0

我該如何從鏈外引發錯誤?如果用戶啓動一個新鏈,我需要取消當前鏈。 – panthro

0

有趣的小挑戰!

不知道你正在啓動哪個任務,請求或過程,以及用戶如何中斷上述過程,很難推薦任何解決方案來「破壞」鏈,而不做一些破解/誘騙, .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種可能的狀態。

  • 如果它是1:它解決了(進入你的「那麼」)
  • 如果是-1:它拒絕(跳到你的「抓」)
  • 否則,它只是不斷循環使用瀏覽器的requestAnimationFrame(...)方法。 (主要是setTimeout(...)已校準,以觸發每個屏幕 刷新)。

現在,影響到這些狀態隨時間的變化如何,我證明了這一點,通過使用ESCAPE作爲中斷狀態(-1)和2秒運行一次的計時器。一旦完成,定時器返回狀態(1)。

不確定它可以滿足您的需求,但可能對任何試圖通過某些外部/異步因素破壞Promise的人有用。