AngularJS Provider依赖注入 - 在提供程序中使用$ log

时间:2015-02-20 02:54:48

标签: javascript angularjs dependency-injection

问题很简单:使用AngularJS,我们无法将$ log注入提供程序。

angular.module('my.module', [])
    .provider('myProvider', function ($log, $logProvider) {
        $log.log("Aloha!"); // Unknown provider: $log
        $logProvider.log("Hi!"); // undefined is not a function: $logProvider has no `log` method 
        this.$get = function($log) {
            $log.log("Hello!"); // Everything is ok here
        };
    });

是的,我们可以注入$logProvider,但它没有必要的方法(.log.error等。)

是的,我们可以注入$logProvider,然后手动调用$logProvider.$get(),但我们将无法使用装饰器的其他逻辑。

是的,我们可以编写自己的logProvider,但我想知道为什么Angular不支持开箱即用的这个功能。

因此,我们无法以真正的角度方式使用控制台'在提供者?这个事实很奇怪。而且很伤心。

问题:我需要如何使用控制台"真正的角度方式"在提供者?

我无法找到有关此问题的任何解释。 Angular Developers Guide说我们需要在每个地方使用$ log而不是console。

2 个答案:

答案 0 :(得分:15)

提供者在创建任何服务之前运行得太早,或者换句话说,提供者的$ get是服务构造函数,它在模块的配置阶段之后被实例化(并且在第一次通过依赖项访问它时注入注入器实例化构造函数并将其保持为单例)。并且提供程序在配置阶段期间或之前运行(因为提供程序方法用于在模块的config阶段配置服务)。这意味着$ log服务尚不可用。

$logProvider.$get将为您提供logservice的构造函数,您可以通过调用$injector.instantiate($logProvider.$get)来创建它的实例,但问题是它依赖于尚未实例化的窗口服务,所以最终你的记录器实例化将会失败。

所以我能想到的一种方法是从另一个注射器获得$ log,即angular.injector(['ng']).get('$log')

angular.module('my.module', [])
  .provider('myProvider', function ($log, $logProvider) {
    var $log =  angular.injector(['ng']).get('$log');
    $log.log("Aloha!"); 

    this.$get = function($log) {
        $log.log("Hello!"); // Everything is ok here
    };
});

<强> Plnkr

或者另一种方式就是疯狂地实例化它,在这种情况下实例化其依赖服务它只是 $ window (甚至提供全局窗口对象为当地人)。

 .provider('myProvider', function ($logProvider,$injector, $windowProvider) {
    //get window service, if you want to really provide window service instance itself, or just provide the global window object
    var window = $injector.instantiate($windowProvider.$get);
    //Get log provider providing locals for $window
    var $log =  $injector.instantiate($logProvider.$get,{$window:window})

    $log.log("Aloha!");// Everything is ok here too

    this.$get = function($log) {
        $log.log("Hello!"); // Everything is ok here
    };

});

<强> Plnkr

只是添加一个不同的注释:在应用程序的配置阶段尝试访问$log服务时,您将看到相同的行为。但有时由于decorators的工作方式,您仍然可以通过使用虚拟装饰器强制创建早期服务来使用它。

即:

.config(function($provide){
   //Just a dummy decorator
   $provide.decorator('$log', function($delegate){
      return $delegate;
  });

}).config(function($logProvider){
   //get logger instance
   var log = $logProvider.$get();
   log.debug("Got it");
});

<强> Plnkr

所以最终的想法是,当你需要在实例化之前使用服务时,你需要通过解析它的所有依赖关系来手动实例化它等等。

答案 1 :(得分:0)

你可以编写一个包装服务说logger,它可以有日志,警告,调试等方法,并在需要的地方注入你的记录器服务,你可以在那里进行格式化

例如: 下面的方法是在我的记录器服务中调用它只是注入记录器和调用日志方法。

this.log = function () {
        if (this.debuggingEnabled) {
           for (var i = 1; i < arguments.length; i++) {
              $log.log("[" + $filter('date')(new Date(), this.format) + "] -- " + arguments[0] + " -- " + JSON.stringify(arguments[i]));
           }
        }
     };