2016-07-08 100 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

这可能有一些其他非常有用的应用程序,但通过这种方法,我得到了“随机”数据(取决于承诺需要解析的时间)而不是最新的。所以它不会回答这个问题,除非我错过了一些东西。 –