【问题标题】:AngularJS $http promise exception not bubbling upAngularJS $http 承诺异常不会冒泡
【发布时间】:2016-03-10 21:00:11
【问题描述】:

我遇到了一个问题,$http Promise 没有从执行它的服务冒泡到调用服务方法的任何地方。

我在服务中有一个.authozire() 方法返回$http Promise,如下:

// auth.service.js

function authorize(authParams) {
  var request = {
    method: 'POST',
    url: _apiUrl + 'oauth/token',
    data: authParams
  };

  return $http(request)
    .then(
      function successHandler(response) {
        // Correctly executed when success
        $log.debug('authService :: authorize => success', response);
      },
      function errorHandler(response) {
        // Correctly executed when error
        $log.debug('authService :: authorize => error', response);
      }
    );
}

上面的 successerror 方法(请不要说我已经不使用 .success().error() 方法,因为它们已被弃用)在每种情况下都可以正常工作,但它不起作用当我从控制器调用此方法时,正如预期的那样:

// signin.controller.js

function submit() {
  authService.authorize(vm.formData)
    .then(
      function successHandler(response) {
        // Always executed even when there's an error
        $log.debug('SignInController :: submit :: authService.authorize() => success', response);
      },
      function errorHandler(response) {
        // NEVER executed
        $log.debug('SignInController :: submit :: authService.authorize() => error', response);
      }
    );
}

第一个方法successHandler 总是被调用,即使出现错误并且服务执行了自己的errorHandler

服务返回的 Promise 似乎只是一个简单的 Promise,它接受 .then(),但不区分 successfail,如文档中所述:

返回一个Promise,当请求成功或失败时,该Promise将被解析为响应对象。

所以...我错过了什么吗?以前有人遇到过这样的问题吗?

谢谢!

【问题讨论】:

  • 您确定将其附加到服务中返回的对象上吗?即 var service = {}; service.submit = 提交;
  • @Katana24:是的,所有内容都根据需要附加并且执行得很好,除非出现错误。在服务中:service = {authorize: authorise}; return service;控制器中:vm.submit = submit;

标签: javascript angularjs


【解决方案1】:

我相信你在我开始了解 Promise 时也有类似的感觉。这是我提出的与您的问题相似的问题的答案。我只是惊讶于错误没有传播。 Using Kris Kowal's Q. How should I catch if any errors have been thrown throughout the life of a chained promise?

引用这个答案:

处理的拒绝就像捕获的异常。它停止传播 既然很好,就处理好了。如果您想处理拒绝和 让它被拒绝,你需要重新抛出,就像在同步中一样 代码。

try {
   throw new Error();
} catch(e){
    // handle error   
}
// no error here this code will keep running.

如果你想让它一直拒绝并处理它,你需要重新抛出:

try {
   throw new Error();
} catch(e){
    // handle error   
    throw e;
}
// this code will not run

promise 也是如此,就像你写的那样。这不是特别 对 Promise 来说很奇怪,这也是同步异常的工作方式。 如果你想传播 - 你重新抛出,否则 - 错误是 视为已处理。

  1. 因此,您可以继续在服务中记录错误,并通过在服务中添加return $q.reject(response); 为链中的下一部分抛出您收到的相同错误。您也可以在服务结束时直接说 throw response; 而无需返回,它会将错误带到链的下一部分。
  2. 您可以决定不在您的服务中记录错误并直接在您的控制器中处理它。

我个人会选择 1,但那是因为我无法忍受当 Promise 没有记录它们的错误时,如果没有记录就很难追踪到什么是破坏。

【讨论】:

  • 感谢您的解释。我想我已经习惯了它如何与 .success().erro() 一起工作,以至于我忘记了 Promise 是如何工作的? 此外,如果您在控制器上需要它,则有必要在 successHandler 上使用 return response.data。跨度>
  • 是的。它们在某些方面与它们的同步对应部分 try catch 非常相似,在学习新概念时很难知道一切应该如何工作。是的,我的意图是,如果你明白我的意思,你可以 throw response; 在你的服务的捕获部分中
  • 有趣的是,这对我来说不是一个新概念,我只是简单地忽略了它们,因为我期待着其他事情发生。不过稍微打开一下思路就好了。 ?
【解决方案2】:

auth.service.jserrorHandler 必须返回被拒绝的promise:

return $q.reject(response);

【讨论】:

  • 您的解决方案有效,但在我接受之前,您介意解释一下原因吗?有什么改变吗?因为它以前是这样工作的。 Angular 只是按原样自动传递 Promise,它可以在链中处理。
  • errorHandler as successHandler 返回可以成功解决或拒绝的承诺。详情见@John 回答,你可以接受他的回答。
【解决方案3】:

问题是您已经在处理身份验证服务中的 promise 回调。

为了解决这个问题,我们有两种可能的解决方案:

在授权方法内部创建一个promise并返回它。

function authorize(params) {
   // create a promise object
   var dfd = $q.defer();

   var request = []; // request params here

   $http(request).then(
   function SuccessHandler(res) {
      def.resolve(res);
   }, 
   function ErrorHandler(res) {
      dfd.reject(res);
   });

   return dfd.promise();
}

另一种方法是发送http对象而不处理方法authorize中的回调

return $http(request);

【讨论】:

    猜你喜欢
    • 2017-09-05
    • 1970-01-01
    • 2011-02-22
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 2011-05-17
    相关资源
    最近更新 更多