在AngularJS中重写运行时的依赖项

时间:2013-10-14 04:23:43

标签: javascript angularjs dependency-injection

我有一个名为$doggedHttp的服务,它公开与$http相同的接口。 现在,我想在$doggedResource而不是$resource之上创建一个$doggedHttp服务,这是一个有角度的$http服务。换句话说,我想将$doggedHttp作为$http服务注入。

此外,在我的应用程序中,我希望能够同时创建$doggedResource$resource。因此,我不能简单地使用$http覆盖$doggedHttp

我认为依赖注入应该使这个场景很容易解决。我错了吗?

相反,我不得不深入研究角度源代码,最终提出了一个非常难看的解决方案:

angular.module('doggedResource', ['ngResource', 'doggedHttp'])
  .config(function() {
    var ngResource = angular.module('ngResource'),
        doggedResource = angular.module('doggedResource');

    // replace the placeholder below with the $resource factory from ngResource
    doggedResource._invokeQueue[1][2][1][2] = ngResource._invokeQueue[0][2][1][2];
})
.factory('$doggedResource', ['$doggedHttp', '$parse', null /* this is just a placeholder */]);

有更好的解决方案吗?


说明我们无法使用$provide.decorator替换已注入的$http服务。 为了说明问题,以下是angular-resource.js的相关部分:

angular.module('ngResource', ['ng']).
  factory('$resource', ['$http', '$parse', function($http, $parse) {

    function ResourceFactory(url, paramDefaults, actions) {
    }

    return ResourceFactory;
  }

查看上面的代码,$provide.decorator回调将作为参数传递给ResourceFactory。那时依赖$http已经解决了。由于ResourceFactory在闭包内使用$http,我们无法改变它。

.config(function($provide) {
  $provide.decorator( '$resource', [ "$delegate", function( $delegate ) {
    // here $delegate is the ResourceFactory which has 
    // already been linked to `$http` by a closure.
  }
}

1 个答案:

答案 0 :(得分:1)

您应该在$doggedHttp的装饰器中编写$http中的所有逻辑。一旦你装饰$http,一切都应该正常

编辑:更正条件。

.config(function($provide) {
  $provide.decorator( '$http', [ "$delegate", function( $delegate ) {
    // here $delegate is the $http function.
    function $doggedHttp(config){
        //write your storage logic here.

        // route all the $http calls through $delegate at the end... 
        return $delegate(config);
    }
    //dont forget to create shortcut method overrides.
    //createShortMethods('get', 'delete', 'head', 'jsonp');
    //createShortMethodsWithData('post', 'put');

    // This is the simplest solution to what you wish to do..
    if( condition ) {
         return $doggedHttp; 
    }
    else { 
         return $delegate;
    }     

    //finally return the $doggedHttp ( and not the $delegate ) 

  }
}

或者,您可以在request interceptor中编写所有存储逻辑 - 您也可以在其中注入任何内容,因此存储您的调用和重新请求也可以在该阶段完成。