How can I extend $q promise in Angularjs with a .success and .error

后端 未结 3 1581
有刺的猬
有刺的猬 2020-12-28 15:37

I wrote this little code in a custom service in AngularJS.

In my service:

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


        
相关标签:
3条回答
  • 2020-12-28 16:15

    If you want to change the default behavior of something that is injected by angular, you can use the decorator() method on the $provide service.

    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;
      });
    });
    

    See the example above in action at http://plnkr.co/edit/RuZF2cGkVHwlu7NIhxEZ?p=preview

    As to modifying $q to add the success and error functions, I am not sure at the moment. But I am pretty sure that this is where you'd want to do it.

    0 讨论(0)
  • 2020-12-28 16:25

    IMHO, @jessegavin 's decoration of $q is not perfect, it shouldn't return origin promise in success&error function. It will lose feature of flatten the callback pyramid.

    And it can't split response data to success&error function $httpPromise dose.

    for example

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

    Here is my version, it will recognize http response and will return the next promise. Make your own $q have the same behavior like $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;
    });
    
    0 讨论(0)
  • 2020-12-28 16:28

    Here's a full solution picking up where @jessegavin left off.

    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;
      });
    
    });
    
    0 讨论(0)
提交回复
热议问题