Зависимость зависимостей оператора AngularJS - использование поставщика $log

Проблема проста: с помощью 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 не поддерживает эту функцию из коробки.

Итак, мы не можем использовать консоль в режиме "true Angular" в провайдере? Этот факт очень странный. И грустно.

Вопрос: как мне нужно использовать консоль в режиме "true Angular" в провайдерах?

Мне не удалось найти объяснений по этой проблеме. Angular Руководство для разработчиков говорит, что нам нужно использовать $log везде вместо консоли.

Ответ 1

Провайдеры запускаются слишком рано до создания каких-либо сервисов или, другими словами, поставщик $get является конструктором службы и получает экземпляр после фазы конфигурации модуля (и когда он получает доступ в первый раз через инъекцию зависимостей, инжектор создает экземпляр конструктор и сохранить его как singleton). И провайдеры работают во время или до фазы конфигурации (поскольку методы провайдера используются для настройки службы во время фазы 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

Итак, в конечном итоге идея состоит в том, что, когда вам нужно использовать службу до того, как она была создана, вам нужно будет вручную ее создать, разрешив все ее зависимости и т.д.

Ответ 2

Вы можете написать сервис-провайдер обертки, который может иметь такие методы, как журнал, предупреждение, отладка и т.д., и вставлять свою службу журналов везде, где это требуется, вы можете сделать там форматирование.

например: Ниже мой внутри службы журнала, чтобы вызвать это, просто введите журнал регистрации и метод журнала вызовов.

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