链接ngResource $承诺成功和错误

时间:2015-03-05 22:28:34

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

我想知道是否可以在多个级别上处理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

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

3 个答案:

答案 0 :(得分:4)

问题是你的服务。改变这个:

  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),它将返回一个包含错误处理程序的新promise。之后,在您的控制器中,您可以像这样添加链。

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

此时完整的承诺链看起来是否展开:

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

由于您使用aResource.save()errorFnFromService收到错误,因此此时承诺链基本上是“干净的”,它将继续下一个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以查看它对输出的影响。

答案 1 :(得分:1)

$q上添加依赖项,并使用$q.reject来控制执行......

在您的示例中,您需要$q.reject方法

中的aService.error

如上所述here in the $q docs

  

reject(reason);

     

创建一个以指定原因解析为已拒绝的承诺。这个api应该用于在一系列承诺中转发拒绝。如果您正在处理承诺链中的最后承诺,您不必担心它。

     

将deferreds / promises与熟悉的try / catch / throw行为进行比较时,请将reject视为JavaScript中的throw关键字。这也意味着,如果你&#34;赶上&#34;通过promise错误回调发生错误,并且您希望将错误转发给从当前承诺派生的承诺,您必须&#34;重新抛出&#34;返回通过拒绝构建的拒绝错误。

答案 2 :(得分:1)

为了正确链接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]);