【问题标题】:chaining ngResource $promise success and errors链接 ngResource $promise 成功和错误
【发布时间】:2015-05-07 11:34:57
【问题描述】:

我想知道是否可以在多个级别上处理 ngResource 返回的$promise,以便代码是 DRY

这是一个简单的例子

aService = function(aResource) {
  var error, success;
  success = function(response) {
    console.log('Service Success');
  };
  error = function(response) {
    console.log('Service Error');
  };

  this.servicePostReq = function() {
    return aResource.save().$promise.then(success, error);
  };
  return this;

angular.module('app.service').factory('aService', ['aResource', aService]);

到目前为止,这工作正常......当响应正常时它Service Success,当响应不正常时它Service Error

但是当我添加一个使用 aService 的控制器时,如下所示

aController = function(aService) {
  var error, success;
  success = function(response) {
    console.log('Controller Success');
  };
  error = function(response) {
    console.log('Controller Error');
  };
  this.controllerPostReq = function() {
    aService.servicePostReq().then(success, error);
  };

  return this;
};

angular.module('app.controller').controller('aController', ['aService', aController]);

控制器总是成功...

所以如果请求返回成功输出是

Service Success
Controller Success

如果请求失败,输出是

Service Error
Controller Success

我如何链接承诺,这样我就不必为每个使用服务的控制器添加服务中处理的代码?

【问题讨论】:

    标签: angularjs angularjs-service angularjs-controller angular-promise ngresource


    【解决方案1】:

    添加对$q的依赖并使用$q.reject来控制执行...

    在您的示例中,您需要在 aService.error 方法中使用 $q.reject

    如上所述here in the $q docs

    reject(reason);

    创建一个以指定原因被拒绝的承诺。这个 api 应该用于在一系列 Promise 中转发拒绝。如果您正在处理 Promise 链中的最后一个 Promise,则无需担心。

    当将 deferreds/promises 与熟悉的 try/catch/throw 行为进行比较时,可以将拒绝视为 JavaScript 中的 throw 关键字。这也意味着,如果您通过 promise 错误回调“捕获”错误,并且希望将错误转发到从当前 promise 派生的 promise,则必须通过返回通过拒绝构造的拒绝来“重新抛出”错误。

    【讨论】:

      【解决方案2】:

      为了正确链接承诺,成功和错误处理程序都应该返回一些值。返回值会自动包装在一个新的 Promise 中。这意味着在出现错误的情况下,您必须使用 $q.reject 返回一个被拒绝的承诺。

      所以你的服务应该是这样的:

      aService = function($q, aResource) {
        var error, success;
        success = function(response) {
          // important! return a value, handlers down the chain will
          // execute their success handlers and receive this value
          return 'Service Success';
        };
        error = function(response) {
          // important! return a REJECTION, handlers down the chain will
          // execute their error handlers and receive this value
          return $q.reject('Service Error');
        };
      
        this.servicePostReq = function() {
          return aResource.save().$promise.then(success, error);
        };
        return this;
      
      angular.module('app.service').factory('aService', ['$q', 'aResource', aService]);
      

      【讨论】:

      • 虽然我同意你的大部分回答,但我对为什么 aService.success 方法不使用 $q.resolve() 而 aService.error 使用 $q.reject() 感到困惑。
      • 这仍然行不通。原因是因为aResource.save().$promise.then(success, error) 既是thenable 又包含一个错误处理程序。无论是否有错误,任何链接到那里的 .then 语句都将运行。 this Plunkr 中的示例(打开控制台查看输出)。
      【解决方案3】:

      问题在于您的服务。改变这个:

        this.servicePostReq = function() {
          return aResource.save().$promise.then(success, error);
        };
      

      到这里:

        this.servicePostReq = function() {
          return aResource.save().$promise.then(success);
        };
      

      说明:

      由于您的服务返回aResource.save().$promise.then(success, error),它返回了一个包含错误处理程序的新承诺。稍后,在您的控制器中,您可以像这样添加到链中。

      aService.servicePostReq().then(success, error);
      

      如果将其展开,此时完整的 Promise 链看起来:

      return aResource.save().$promise
        .then(successFnFromService, errorFnFromService)
        .then(successFnFromController, errorFnFromController);
      

      由于您使用errorFnFromService 捕获了来自aResource.save() 的错误,因此此时承诺链基本上是“干净的”,它将继续下一个then

      通过删除第一个错误处理程序,您可以稍后捕获错误。

      处理 Promise 链中错误的更好方法(通常)是在链的末尾使用单个 .catch()。

      考虑一下这个糟糕的代码(尝试在浏览器控制台上运行):

      new Promise(
        function(resolve, reject){
          reject('first');
        }).then(
          function(result) {
            console.log('1st success!', result);
            return result;
          },
          function(err) {
            console.log('1st error!', err);
            return err;
          }
        ).then(
          function(result){
            console.log('2nd success!', result);
          },
          function(err){
            console.log("2nd error!", err);
          }
        );
      

      输出:

      1st error! first
      2nd success! first
      

      更好的方法:

      new Promise(
        function(resolve, reject){
          reject('first');
        }).then(function(result) {
          console.log('1st success!', result);
          return result;
        }).then(function(result){
          console.log('2nd success!', result);
        // catch error once at the end
        }).catch(function(err){
          console.log("error!", err);
        });
      

      输出:

      error! first
      

      在浏览器控制台中尝试这两种方法,并将 reject 更改为 resolve 以查看它对输出的影响。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-10
        • 2018-06-30
        • 1970-01-01
        • 1970-01-01
        • 2016-01-17
        • 2017-08-09
        • 2012-09-18
        • 1970-01-01
        相关资源
        最近更新 更多