【问题标题】:Detect existence of next handler in Angular JavaScript promise chain检测 Angular JavaScript 承诺链中是否存在下一个处理程序
【发布时间】:2014-10-07 06:38:45
【问题描述】:

给定以下两个$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) {});

[注意:示例二不包含错误处理程序]

还有一个位于所有$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() 不包含错误回调时,如何使拦截器不拒绝?如果回调在exampleOne 中存在,那么我希望拒绝,但如果在exampleTwo 中不存在,那么我希望重定向到错误页面,从而将条件更改为:

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

为什么?因为我的项目中只有某些情况需要以用户友好的方式处理400,因此我想消除许多重复的错误回调或不得不在拦截器中放置一个不常见情况的列表。我希望拦截器能够根据承诺链中另一个处理程序的存在来做出决定。

【问题讨论】:

    标签: javascript angularjs promise angular-http-interceptors


    【解决方案1】:

    简单地说这是不可能的,你无法检测到是否有人会在未来的某个时间附加一个处理程序,就像你无法判断你是否在函数中 throw 时一样是否会在外面被抓住。 不过,你想做的事都可以做到

    这不是一个“菜鸟问题”,而是非常基础的:

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

    首先,你能做什么

    简单的放在第一种情况:

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

    你得到的是一个总是实现的承诺。但是,在第二种情况下,promise 可能会被拒绝。使用拒绝处理程序处理拒绝就像实际代码中的catch - 一旦处理它就不再被拒绝。

    就个人而言,我不会在这里使用拦截器,而是使用资源使用模式,因为它的意图更清晰,您可以将它包装在一个函数中,这样它就不需要作用域,但我不太喜欢这个想法。这就是我要做的事情

    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 的代码,我们创建一个新的 Promise p 并将 M 中的每个 return 语句和 M 中的throw 语句替换为 return p.catch(function(){}) 并添加一个 @987654331 @,现在当且仅当运行 M 终止时,处理程序将添加到 p。所以简而言之 - 给定代码 M,我们已经构建了一种方法来查看它是否基于存在解决问题的解决方案来判断是否将 catch 附加到 p - 所以这个问题至少和 @ 一样难987654321@.

    【讨论】:

    • 请注意,可以解决许多停止问题的实例。用同音语言编写一个语句来测试它是否是从包含在 try-catch 子句中的某个地方调用的语句将是真正有趣 :-)
    【解决方案2】:

    也许你可以用零超时推迟重定向,并给错误处理程序一个机会(如果存在)在错误处理的错误对象上设置标志:

    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+ Promises 已经推迟执行。
    • @BenjaminGruenbaum 我在本地对此进行了测试,虽然我预计 finally 块将在承诺链的末尾执行,但它是在就地错误处理程序之前执行的。
    • 是的,但它是在错误处理程序附加之后执行的。有人可以在以后的某个时间点附加错误处理程序。
    • 我不关注你。随时用示例编辑我的答案。
    • 我的第一点是,如果您以某种方式检测到将.catch 添加到链中,您的代码将起作用。如果你不这样做 - 我总是可以提供一个反例,例如 var p = promise(); setTimeout(function(){ p.catch(function{}),2000) - 它不会检测到。
    猜你喜欢
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 2014-06-10
    • 2014-11-24
    相关资源
    最近更新 更多