问题:
是否有一种“简单”的方法可以取消AngularJS中的承诺($q
- / $http
- )或确定承诺的解决顺序?
示例
我有一个长时间运行的计算,我通过$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-object,使用一些时间戳或其他标识符来手动排序传入的响应。然而,我希望我能以某种方式告诉角度取消过时的承诺,因此当它被解析时不会运行.then()函数。
如果没有$q
的手动实现,这不起作用 - 承诺而不是$http
。
也许只是拒绝承诺就是要走的路?但在这两种情况下,它可能需要永远,直到最终在生成下一个请求之前解决了一个promise(在此期间会导致一个空视图)。
是否存在一些我缺少的角度API函数,或者是否存在强大的设计模式或带有promise链接的“技巧”或$ q.all来处理返回“相同”数据的多个promise?
答案 0 :(得分:4)
取消承诺只是让它不会在onFulfilled
阶段调用onRejected
和then
函数。因此,@ user2263572提到它总是最好放弃未取消的承诺(无论如何都无法取消ES6原生承诺)并在then
阶段处理这个条件(如果全局变量设置为2则忽略任务)如下面的代码段所示,我相信你可以找到很多其他方法来实现它。一个例子可能是;
很抱歉,对v
resolve
使用x
(看起来像是核对字符),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));
(显而易见)。
src/main/scala
答案 1 :(得分:4)
我是通过生成requestId
来实现的,并在promise的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)
方法中,我做了一个这样的过程:
requestId
。 检入requestId
requestId
:在哈希表中生成新请求和存储承诺requestId
:只需从哈希表中返回承诺请求完成后,从哈希表中删除requestId
的条目。
答案 2 :(得分:0)
我仍在尝试找出一种好的单元测试方法,但你可以尝试这种策略:
var canceller = $q.defer();
service.sendCalculationRequest = function () {
canceller.resolve();
return $http({
method: 'GET',
url: '/do-calculation',
timeout: canceller.promise
});
};
答案 3 :(得分:0)
在ECMA6承诺中,there is a Promise.race(promiseArray)
method。这需要一组promises作为参数,并返回一个promise。在数组中解析的第一个承诺会将其解析后的值移交给返回的promise的.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);
});
你可以将它与Promise polyfil一起使用,或look into the q.race that someone's developed for Angular(虽然我还没有测试过它)。