2016-07-08 29 views
5

問題的承諾:秩序AngularJS

是否有一個「簡單」的方式取消($q -/$http - )承諾在AngularJS或確定的順序失信得到解決?

我有一個長期運行的計算和I請求經由$http結果。某些操作或事件要求我重新開始計算(並因此發送新的$http請求),然後解決初始承諾。因此,我想我不能用一個簡單的實現像

$http.post().then(function(){ 
    //apply data to view 
}) 

,因爲我不能保證回覆回來的,我做到了發送請求的順序 - 畢竟我要顯示的結果當所有承諾得到妥善解決時的最新計算。

但是我想避免等待第一個響應,直到我發這樣一個新的請求:

const timeExpensiveCalculation = function(){ 
    return $http.post().then(function(response){ 
     if (isNewCalculationChained) {return timeExpensiveCalculation();}    
     else {return response.data;} 
    }) 
} 

思考:

當使用$http我可以訪問config-對象使用一些時間戳或其他標識符來手動排序傳入響應。不過,我希望我可以以某種方式告訴角色取消過時的承諾,因此不會在解析後運行.then()函數。

儘管如此,如果沒有手動執行$q而不是$http,那麼這不起作用。

也許只是立即拒絕承諾就是要走的路?但是在這兩種情況下,它可能會一直持續下去,直到在下一個請求產生之前最終解決承諾(在此期間導致空視圖)。

是否存在一些我缺少的角度API函數,或者是否存在強大的設計模式或帶有承諾鏈接的「技巧」或$ q.all來處理返回「相同」數據的多個承諾?

+0

不知道你用什麼API,但在我的.net apis我用SignalR來處理這樣的場景。 – jbrown

+1

偉大的問題,期待着答案。但是,如果處理邏輯內部的邏輯不是很容易,而不是試圖避免承諾解決? – user2263572

+0

[Promise可能重複 - 是否可以強制取消承諾](http://stackoverflow.com/questions/30233302/promise-is-it-possible-to-force-cancel-a-promise) –

回答

3

我這樣做是通過產生一個requestId,並在承諾的then()功能我是否響應從最近requestId到來。

儘管這種方法實際上並未取消先前的承諾,但它確實提供了一種快速而簡單的方法來確保您處理最近請求的響應。

喜歡的東西:

var activeRequest; 
function doRequest(params){ 
    // requestId is the id for the request being made in this function call 
    var requestId = angular.toJson(params); // I usually md5 hash this 

    // activeRequest will always be the last requestId sent out 
    activeRequest = requestId; 

    $http.get('/api/something', {data: params}) 
     .then(function(res){ 
      if(activeRequest == requestId){ 
       // this is the response for last request 

       // activeRequest is now handled, so clear it out 
       activeRequest = undefined; 
      } 
      else { 
       // response from previous request (typically gets ignored) 
      } 
     }); 
} 

編輯: 在一個側面說明,我想補充一點,跟蹤requestId's這一概念也能夠適用於防止重複請求。舉例來說,在我的Data服務的load(module, id)方法,我做一個小的過程是這樣的:

  1. 基於URL +參數生成requestId
  2. 在請求哈希表檢查爲requestId

    • 如果requestId未發現:產生哈希表
    • 如果requestId新的請求和存儲的承諾被發現:單純從哈希返回的承諾-table
  3. 當請求結束時,從散列表中刪除requestId的條目。

+0

非常感謝!我會接受這個答案,因爲它實際上是指我所要求的angularJS。Redu的回答包含了這個技術的一個工作例子(不使用Angular) –

4

取消承諾只是使其不會調用then階段的onFulfilledonRejected函數。因此,@ user2263572提到最好放棄未取消的承諾(ES6原生承諾無法取消),並在then階段處理此情況(如忽略任務,如果全局變量設置爲2,如下面的片段),我相信你可以找到很多其他的方式來做到這一點。一個例子可能是;

對不起,我使用v(看起來像檢查字符)爲resolvex(顯而易見)爲reject函數。

var prom1 = new Promise((v,x) => setTimeout(v.bind(null,"You shall not read this"),2000)), 
 
     prom2, 
 
validPromise = 1; 
 
prom1.then(val => validPromise === 1 && console.log(val)); 
 
// oh what have i done..!?! Now i have to fire a new promise 
 
prom2 = new Promise((v,x) => setTimeout(v.bind(null,"This is what you will see"),3000)); 
 
validPromise = 2; 
 
prom2.then(val => validPromise === 2 && console.log(val));

0

我還在試圖找出單元測試一個很好的方式,但你可以嘗試這種策略:

var canceller = $q.defer(); 
service.sendCalculationRequest = function() { 
    canceller.resolve(); 
    return $http({ 
     method: 'GET', 
     url: '/do-calculation', 
     timeout: canceller.promise 
    }); 
}; 
+0

我在發佈這個問題後在另一個線程中發現了這個。儘管如此,這仍然只適用於'$ http'調用。 –

+0

啊我看到了,所以你正在用'$ resource'尋找東西。 –

0

在ECMA6承諾,there is a Promise.race(promiseArray) method。這需要一系列承諾作爲參數,並返回一個承諾。在數組中解決的第一個承諾是將解決的值交給返回的承諾的.then,而另一個承諾第二個等等的承諾將不會被等待。

例子:

var httpCall1 = $http.get('/api/something', {data: params}) 
    .then(function(val) { 
     return { 
      id: "httpCall1" 
      val: val 
     } 
    }) 
var httpCall2 = $http.get('/api/something-else', {data: params}) 
    .then(function(val) { 
     return { 
      id: "httpCall2" 
      val: val 
     } 
    }) 
// Might want to make a reusable function out of the above two, if you use this in Production 
Promise.race([httpCall1, httpCall2]) 
    .then(function(winningPromise) { 
     console.log('And the winner is ' + winningPromise.id); 
     doSomethingWith(winningPromise.val); 
    }); 

你既可以用無極polyfil,或look into the q.race that someone's developed for Angular用這個(雖然我沒有測試過)。

+0

這可能有一些其他非常有用的應用程序,但通過這種方法,我得到了「隨機」數據(取決於承諾需要解析的時間)而不是最新的。所以它不會回答這個問題,除非我錯過了一些東西。 –