Javascript 检测链中是否存在下一个处理程序
给出以下两个Javascript 检测链中是否存在下一个处理程序,javascript,angularjs,promise,angular-http-interceptors,Javascript,Angularjs,Promise,Angular Http Interceptors,给出以下两个$resource示例: var exampleOne = $resource('/path').save(objectOne); exampleOne.$promise.then(function (success) {}, function (error) {}); var exampleTwo = $resource('/path').save(objectTwo); exampleTwo.$promise.then(function (success) {}); [注意:
$resource
示例:
var exampleOne = $resource('/path').save(objectOne);
exampleOne.$promise.then(function (success) {}, function (error) {});
var exampleTwo = $resource('/path').save(objectTwo);
exampleTwo.$promise.then(function (success) {});
[注意:示例2不包含错误处理程序]
以及位于所有$http
请求下方的拦截器:
var interceptor = ['$location', '$q', function ($location, $q) {
function error(response) {
if (response.status === 400) {
return $q.reject(response);
}
else {
$location.path('/error/page');
}
return $q.reject(response);
}
return {
'responseError': error
};
}
$httpProvider.interceptors.push(interceptor);
当示例资源$promise.then()
不包含错误回调时,如何使拦截器不被拒绝?如果回调存在于示例一
中,则我希望拒绝,但如果不是在示例二
中,则我希望重定向到错误页面,从而将条件更改为类似以下内容:
if (response.status === 400 && $q.unresolvedPromises.doIndeedExist()) { ...
为什么??因为在我的项目中只有一些情况需要以用户友好的方式处理
400
,因此我想消除许多重复的错误回调,或者必须在拦截器中放置一个不常见情况的列表。我希望拦截器能够根据承诺链中是否存在另一个处理程序来做出决定。简单地说,这是不可能的,您无法检测将来是否有人会在某个时候附加处理程序,就像您无法判断当您在函数中抛出时,它是否会被外部捕获一样但是,您想做的事情是可以做到的
这不是一个“noob问题”,而是一个非常基本的问题:
function foo()
throw new Error(); // I want to know if whoever is calling `foo`
// handles this error
}
首先,你能做什么
简单地说,在第一种情况下:
exampleOne.$promise.then(function (success) {}, function (error) {});
你得到的是一个永远都会实现的承诺。然而,在第二种情况下,承诺可能会被拒绝。用拒绝处理程序处理拒绝就像是真实代码中的捕获,一旦你处理了它,它就不再被拒绝
就我个人而言,我不会在这里使用拦截器,而是使用一种资源使用模式,因为这更清楚,你可以将它包装在一个函数中,这样它就不需要作用域,但我不太喜欢这种想法。这就是我要做的
attempt(function(){
return $resource('/path').save(objectTwo).$promise.
then(function (success) {});
});
function attempt(fn){
var res = fn();
res.catch(function(err){
// figure out what conditions you want here
// if the promise is rejected. In your case check for http errors
showModalScreen();
}
return res; // for chaining, catch handlers can still be added in the future, so
// this only detects `catch` on the function passed directly so
// we keep composability
}
现在,一个简短的证据证明这是不可能的
为了好玩,让我们来证明一下
假设给我们一个程序M的代码,我们创建一个新的promisep
,并将M中的每个return
语句和M中的throw
语句替换为returnp.catch(function(){})
,还添加了一个returnp.catch(function(){})
,现在,当且仅当运行M
终止时,将向p
添加一个处理程序。因此,简言之,给定代码M,我们构建了一种方法来查看它是否会停止,这是基于一个解决方案的存在,该解决方案用于查找catch
是否附加到p
,因此这个问题至少与p一样难。也许您可以在零超时的情况下延迟重定向,并给错误处理程序一个机会,如果存在的话,设置标志已处理错误的错误对象:
var interceptor = ['$q', '$timeout', function ($q, $timeout) {
function error(rejection) {
return $q.reject(rejection).finally(function () {
$timeout(function () {
if (rejection.errorHandled === true) {
alert('all is under control');
} else {
alert("Houston we've got problems");
}
}, 0); //zero timeout to execute function after all handlers in chain completed
});
}
return {
'responseError': error
};
}];
var exampleOne = $resource('/path').save(objectOne);
exampleOne.$promise.then(function (success) { }, function(error) {
error.errorHandled = true;
});
为什么这里的$timeout
?A+承诺已经将执行推迟到稍后的时间。@BenjaminGruenbaum我在本地测试了这一点,虽然我预期finally
块将在承诺链的末尾执行,但它是在就地错误处理程序之前执行的。是的,但它是在附加错误处理程序之后执行的。有人可以在将来的某个时候附加一个错误处理程序。我不明白你的意思。请随意用示例编辑我的答案。我的第一点是,如果您以某种方式检测到向链中添加.catch
,那么您的代码将起作用。如果您不这样做,我总是可以生成一个反例,例如var p=promise();setTimeout(function(){p.catch(function{}),2000)
-它不会检测到。请注意,许多停止问题的实例都可以解决。用同象性语言编写一个语句,测试是否从try-catch子句中包装的某个位置调用它,这将是一件非常有趣的事情:-)