如何使用 .success 和 .error 在 Angularjs 中扩展 $q 承诺

Posted

技术标签:

【中文标题】如何使用 .success 和 .error 在 Angularjs 中扩展 $q 承诺【英文标题】:How can I extend $q promise in Angularjs with a .success and .error 【发布时间】:2013-05-23 17:29:34 【问题描述】:

我在 AngularJS 的自定义服务中编写了这个小代码。

为我服务:

        var deferred = $q.defer();
        var promise = deferred.promise;

        deferred.resolve('success');
        deferred.reject('error');

        /* Handle success and error */
        promise.success = function(fn) 

            promise.then(function(response) 

                fn(response);

            );

            return promise;
        ;

        promise.error = function(fn) 

            promise.then(null, function(response) 

                fn(response);

            );

            return promise;
        ;

在我的控制器中:

        promiseService.myPromise()
            .success(function(data)

                $scope.success= data;

            )
            .error(function(data)

                $scope.error = data;

            );

我只是从承诺($q 服务)中处理成功和错误。我在很多其他服务中都需要此代码,因此我将直接使用自定义扩展 $q 服务。

所以我想在我的服务中使用这样的东西:

    var deferred = myPromiseService.$qCustom.defer();
    var promise = deferred.promise;

    deferred.resolve('success');
    deferred.reject('error');

    return promise;

有什么想法吗?我找到了一些在 Angularjs 中扩展过滤器的解释,我的问题是找到扩展 $q 的所有功能并添加我的自定义的好方法。

我从类似的东西开始,开箱即用地处理 $q :

angular.module('myApp').service('myPromiseService', function($q)

  $qCustom = $q;  

);

【问题讨论】:

【参考方案1】:

这是一个完整的解决方案,从@jessegavin 停止的地方开始。

var myApp = angular.module("myApp", []);

myApp.config(function ($provide) 

  $provide.decorator('$q', function ($delegate) 
    var defer = $delegate.defer;
    $delegate.defer = function () 
      var deferred = defer();
      deferred.promise.success = function (fn) 
        deferred.promise.then(function(response) 
          fn(response.data, response.status, response.headers);
        );
      return deferred.promise;
      ;
      deferred.promise.error = function (fn) 
        deferred.promise.then(null, function(response) 
          fn(response.data, response.status, response.headers);
        );
        return deferred.promise;
      ;
      return deferred;
    ;
    return $delegate;
  );

);

【讨论】:

【参考方案2】:

如果你想改变 Angular 注入的东西的默认行为,你可以使用$provide 服务上的decorator() 方法。

var myApp = angular.module("myApp", []);

myApp.config(function ($provide) 
  $provide.decorator("$q", function($delegate) 
    // The $delegate argument here refers to the $q service.

    $delegate.defer = function() 
      alert("You just tried to call defer()!");
    ;

    // Now, every time angular provides an instance of $q via
    // injection, it will return your customized version of $q.

    return $delegate;
  );
);

在http://plnkr.co/edit/RuZF2cGkVHwlu7NIhxEZ?p=preview查看上面的例子

至于修改$q添加成功和错误功能,我目前不确定。但我很确定这就是你想要做的地方。

【讨论】:

【参考方案3】:

恕我直言,@jessegavin 对 $q 的装饰并不完美,它不应该在 success&error 函数中返回 origin 承诺。它会失去扁平化回调金字塔的特性。

并且它不能将响应数据拆分为成功和错误函数 $httpPromise 剂量。

例如

//can't do this..
somePromise.success(function()
  return $http.get(...)//another primise
).success(function(data)
  //data from $http.get..
)

这是我的版本,它会识别 http 响应并返回下一个承诺。 让你自己的 $q 具有与 $httpPromise 相同的行为

$provide.decorator('$q', function($delegate) 
  function httpResponseWrapper(fn) 
    return function(res) 
      if (res.hasOwnProperty('data') && res.hasOwnProperty('status') && res.hasOwnProperty('headers') && res.hasOwnProperty('config') && res.hasOwnProperty('statusText')) 
        return fn(res.data, res.status, res.headers, res.config, res.statusText);
       else 
        return fn(res);
      
    ;
  ;
  function decorator(promise) 
    promise.success = function(fn) 
      return decorator(promise.then(httpResponseWrapper(fn)));
    ;
    promise.error = function(fn) 
      return decorator(promise.then(null, httpResponseWrapper(fn)));
    ;
    return promise;
  ;
  var defer = $delegate.defer;
  $delegate.defer = function() 
    var deferred = defer();
    decorator(deferred.promise);
    return deferred;
  ;
  return $delegate;
);

【讨论】:

也许我的心理 JS 引擎出现了故障,但在我看来,这与 HttpPromise 的行为不同。 HttpPromise should return the original promise,这将返回一个允许链接的新承诺。

以上是关于如何使用 .success 和 .error 在 Angularjs 中扩展 $q 承诺的主要内容,如果未能解决你的问题,请参考以下文章

在.success和.error中使用范围变量

在 AngularJS 中使用带有 Promises 的 success/error/finally/catch

$.ajax()中的success和error的使用注意事项

ThinkPHP3.2.2自定义success及error跳转页面

thinkphp方法success和error跳转时间以及返回ajax

Thinkphp框架中自定义修改success和error页面