简体   繁体   English

检测Angular JavaScript Promise链中下一个处理程序的存在

[英]Detect existence of next handler in Angular JavaScript promise chain

Given the following two $resource examples: 给出以下两个$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) {});

[NOTE: Example two contains no error handler] [注意:示例二不包含错误处理程序]

And an interceptor that sits below all $http requests: 位于所有$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);

How can I make the interceptor not reject when the example resources $promise.then() contain no error callback? 当示例资源$promise.then()包含错误回调时,如何使拦截器不拒绝? If the call back exists as in exampleOne then I wish to reject, but if not as in exampleTwo then I wish to redirect to the error page thus changing the conditional to something like: 如果回调存在在exampleOne然后我想拒绝,但如果不是在exampleTwo然后我想重定向到错误页面从而改变有条件的类似:

if (response.status === 400 && $q.unresolvedPromises.doIndeedExist()) { ...

Why? 为什么? Because only some situations in my project call for handling a 400 in a user friendly way, thus I'd like to eliminate many duplicate error callbacks or having to place a list of uncommon situations in the interceptor. 因为在我的项目中只有某些情况要求以用户友好的方式处理400 ,所以我想消除许多重复的错误回调或在拦截器中放置一些不常见的情况。 I'd like the interceptor to be able to decide based on the presence of another handler in the promise chain. 我希望拦截器能够根据Promise链中另一个处理程序的存在来做出决定。

Simply put it is impossible , you can't detect if someone will attach a handler in some point in the future just like you can't tell if when you throw in a function it will be caught on the outside or not. 简单地说是不可能的 ,你无法检测到是否有人会在一些点在未来的附加处理程序,就像你不能告诉,如果当你throw在一个函数会在外面或不被抓住。 However, what you want done can be done . 但是,您可以完成您想做的事情

It is not a 'noob question', and it is very fundamental: 这不是一个“菜鸟问题”,它是非常基本的:

 function foo()
    throw new Error(); // I want to know if whoever is calling `foo`
                       // handles this error
 }

First, what you can do 首先,你能做什么

Simply put in the first case: 简单地讲第一种情况:

 exampleOne.$promise.then(function (success) {}, function (error) {});

What you get is a promise that is always fulfilled. 您得到的是始终兑现的诺言。 However, in the second case the promise might be rejected. 但是,在第二种情况下,承诺可能会被拒绝。 Handling a rejection with a rejection handler is like a catch in real code - once you handle it it is no longer rejected. 使用拒绝处理程序处理拒绝就像是真实代码中的catch -一旦处理它就不再被拒绝。

Personally, I would not use an interceptor here, but rather a resource-using pattern since that's more clear with intent, you can wrap it in a function so it won't need a scope but I like that idea less. 就个人而言,我不会在这里使用拦截器,而是使用一种资源使用模式,因为使用意图可以更清楚地了解这一点,您可以将其包装在一个函数中,这样就不需要作用域,但是我不太喜欢这个想法。 Here is what I'd do 这就是我要做的

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
}

Now, a short proof that it can't be done 现在,简短证明它无法完成

Let's prove it for fun. 让我们来证明它的乐趣。

Let's say we are given the code of a program M, we create a new promise p and replace every return statement in M and throw statement in M with a return p.catch(function(){}) and also add a return p.catch(function(){}) , now a handler will be added to p if and only if running M ever terminates. 假设我们得到了程序M的代码,我们创建了一个新的promise p并用return p.catch(function(){})替换了M中的每个return语句,并将M中的throw语句替换了,还添加了return p.catch(function(){}) ,现在且仅当运行M终止时,处理程序才会添加到p So in short - given code M we have constructed a way to see if it halts based on an existence of a solution to the problem of finding if catch is appended to p - so this problem is at least as hard as the halting problem . 因此,在给定的短代码M中,我们基于找到是否将catch附加到p的问题的解决方案的存在,构造了一种方法来查看其是否停止,因此该问题至少与停止问题一样困难。

Maybe you can postpone redirect with zero timeout and give a chance to error handler if any exists to set flag on error object that error was handled: 也许您可以使用零超时来推迟重定向,并给错误处理程序一个机会,如果有的话可以在错误对象上设置已处理错误的标志:

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;
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM