AngularJS 中的承诺顺序
Order of promises in AngularJS
问题:
是否有 "easy" 方法来取消 AngularJS 中的($q
-/$http
-)承诺或确定解决承诺的顺序?
例子
我有一个很长的 运行ning 计算,我通过 $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
时,我可以访问响应上的配置对象,以使用一些时间戳或其他标识符来手动对传入响应进行排序。但是我希望我可以告诉 angular 以某种方式取消过时的承诺,因此当它得到解决时 运行 .then() 函数不会被取消。
如果没有手动实现 $q
-promises 而不是 $http
,这将不起作用。
也许直接拒绝承诺才是正确的选择?但是在这两种情况下,在生成下一个请求之前最终解决承诺可能需要很长时间(同时导致空视图)。
是否有一些 angular API-我缺少的功能或是否有稳健的设计模式或 "tricks" 具有承诺链或 $q.all 来处理多个承诺return "same" 数据?
取消承诺只是让它在then
阶段不调用onFulfilled
和onRejected
函数。因此,正如@user2263572 提到的那样,最好放弃未取消的承诺(ES6 原生承诺无论如何都不能取消)并在 then
阶段处理这种情况(比如如果全局变量设置为 2,则忽略任务如以下代码片段所示),我相信您可以找到许多其他方法来做到这一点。一个例子可以是;
抱歉,我对 resolve
使用 v
(看起来像检查字符),对 reject
函数使用 x
(很明显)。
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));
我通过生成一个 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)
方法中,我做了一个像这样的小过程:
- 根据 URL + 参数生成
requestId
。
签入 requestId
的请求哈希-table
- 如果未找到
requestId
:生成新请求并在散列中存储 promise-table
- 如果找到
requestId
:只需 return 来自散列的承诺-table
请求完成后,从散列中删除 requestId
的条目-table。
我仍在尝试找出一种对此进行单元测试的好方法,但您可以尝试这种策略:
var canceller = $q.defer();
service.sendCalculationRequest = function () {
canceller.resolve();
return $http({
method: 'GET',
url: '/do-calculation',
timeout: canceller.promise
});
};
在 ECMA6 承诺中,there is a Promise.race(promiseArray)
method。这将一系列承诺作为其参数,并且 returns 是一个单一的承诺。数组中第一个解析的承诺会将其已解析的值传递给返回的承诺的 .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(尽管我还没有测试过)。
问题:
是否有 "easy" 方法来取消 AngularJS 中的($q
-/$http
-)承诺或确定解决承诺的顺序?
例子
我有一个很长的 运行ning 计算,我通过 $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
时,我可以访问响应上的配置对象,以使用一些时间戳或其他标识符来手动对传入响应进行排序。但是我希望我可以告诉 angular 以某种方式取消过时的承诺,因此当它得到解决时 运行 .then() 函数不会被取消。
如果没有手动实现 $q
-promises 而不是 $http
,这将不起作用。
也许直接拒绝承诺才是正确的选择?但是在这两种情况下,在生成下一个请求之前最终解决承诺可能需要很长时间(同时导致空视图)。
是否有一些 angular API-我缺少的功能或是否有稳健的设计模式或 "tricks" 具有承诺链或 $q.all 来处理多个承诺return "same" 数据?
取消承诺只是让它在then
阶段不调用onFulfilled
和onRejected
函数。因此,正如@user2263572 提到的那样,最好放弃未取消的承诺(ES6 原生承诺无论如何都不能取消)并在 then
阶段处理这种情况(比如如果全局变量设置为 2,则忽略任务如以下代码片段所示),我相信您可以找到许多其他方法来做到这一点。一个例子可以是;
抱歉,我对 resolve
使用 v
(看起来像检查字符),对 reject
函数使用 x
(很明显)。
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));
我通过生成一个 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)
方法中,我做了一个像这样的小过程:
- 根据 URL + 参数生成
requestId
。 签入
的请求哈希-tablerequestId
- 如果未找到
requestId
:生成新请求并在散列中存储 promise-table - 如果找到
requestId
:只需 return 来自散列的承诺-table
- 如果未找到
请求完成后,从散列中删除
requestId
的条目-table。
我仍在尝试找出一种对此进行单元测试的好方法,但您可以尝试这种策略:
var canceller = $q.defer();
service.sendCalculationRequest = function () {
canceller.resolve();
return $http({
method: 'GET',
url: '/do-calculation',
timeout: canceller.promise
});
};
在 ECMA6 承诺中,there is a Promise.race(promiseArray)
method。这将一系列承诺作为其参数,并且 returns 是一个单一的承诺。数组中第一个解析的承诺会将其已解析的值传递给返回的承诺的 .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(尽管我还没有测试过)。