Spec-Zone.ru › Angular.js 1.2

Улучшить эту документациюСервисы

Угловые сервисы — это заменяемые объекты, которые связываются с помощью инъекции зависимостей (DI). Вы можете использовать сервисы для организации и совместного использования кода в приложении.

Угловые сервисы:

  • Инициализируются лениво — Angular инициализирует сервис только тогда, когда компонент приложения зависит от него.
  • Являются синглтонами — каждый компонент, зависящий от сервиса, получает ссылку на единственный экземпляр, сгенерированный фабрикой сервиса.

Angular предоставляет несколько полезных сервисов (например, $http), но для большинства приложений вам также нужно будет создать свои собственные.

Примечание: Как и другие встроенные идентификаторы Angular, встроенные сервисы всегда начинаются с $ (например, $http).

Использование сервиса

Для использования углового сервиса добавьте его в качестве зависимости для компонента (контроллера, сервиса, фильтра или директивы), который зависит от сервиса. Подсистема инъекции зависимостей Angular позаботится об остальном.

Примечание: Angular использует инъекцию конструктора.

Явная инъекция зависимостей

Компонент должен явно определять свои зависимости, используя один из методов аннотаций инъекции:

  1. Аннотация инъекции массивом (предпочтительный вариант):

    myModule.controller('MyController', ['$location', function($location) { ... }]);
    
  2. $inject свойство:

    var MyController = function($location) { ... };
    MyController.$inject = ['$location'];
    myModule.controller('MyController', MyController);
    
Лучшая практика: Используйте аннотацию массивом, показанную выше.

Неявная инъекция зависимостей

Даже если вы не аннотируете свои зависимости, DI Angular может определить зависимость по имени параметра. Давайте перепишем предыдущий пример, чтобы продемонстрировать использование этой неявной инъекции зависимостей $window, $scope, и нашего сервиса notify:

Внимание: Если вы планируете минифицировать свой код, имена ваших переменных будут переименованы, если вы не используете один из методов аннотации выше.
Если вы используете инструмент, такой как ngmin в своем рабочем процессе, вы можете использовать неявную нотацию зависимостей в своём коде и позволить ngmin автоматически преобразовать такие инжектируемые функции в нотацию массива перед минификацией.

Создание сервисов

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

Функция-фабрика сервиса генерирует единственный объект или функцию, представляющую сервис для остальной части приложения. Объект или функция, возвращаемые сервисом, вводятся в любой компонент (контроллер, сервис, фильтр или директива), который указывает зависимость от сервиса.

Регистрация сервисов

Сервисы регистрируются в модулях через API модуля. Обычно вы используете API Module#factory для регистрации сервиса:

var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
  var shinyNewServiceInstance;
  //factory function body that constructs shinyNewServiceInstance
  return shinyNewServiceInstance;
});

Обратите внимание, что вы регистрируете не экземпляр сервиса, а функцию-фабрику, которая создаст этот экземпляр при вызове.

Зависимости

Сервисы могут иметь свои собственные зависимости. Так же, как вы объявляете зависимости в контроллере, вы объявляете зависимости, указав их в сигнатуре функции-фабрики сервиса.

В примере модуля ниже есть два сервиса, каждый с различными зависимостями:

var batchModule = angular.module('batchModule', []);

/**
 * The `batchLog` service allows for messages to be queued in memory and flushed
 * to the console.log every 50 seconds.
 *
 * @param {*} message Message to be logged.
 */
batchModule.factory('batchLog', ['$interval', '$log', function($interval, $log) {
  var messageQueue = [];

  function log() {
    if (messageQueue.length) {
      $log.log('batchLog messages: ', messageQueue);
      messageQueue = [];
    }
  }

  // start periodic checking
  $interval(log, 50000);

  return function(message) {
    messageQueue.push(message);
  }
}]);

/**
 * `routeTemplateMonitor` monitors each `$route` change and logs the current
 * template via the `batchLog` service.
 */
batchModule.factory('routeTemplateMonitor', ['$route', 'batchLog', '$rootScope',
  function($route, batchLog, $rootScope) {
    $rootScope.$on('$routeChangeSuccess', function() {
      batchLog($route.current ? $route.current.template : null);
    });
  }]);

В примере обратите внимание, что:

  • Сервис batchLog зависит от встроенных сервисов $interval и $log.
  • Сервис routeTemplateMonitor зависит от встроенного сервиса $route и нашего пользовательского сервиса batchLog.
  • Оба сервиса используют нотацию массива для объявления своих зависимостей.
  • Порядок идентификаторов в массиве соответствует порядку имен аргументов в функции-фабрике.

Регистрация сервиса с помощью $provide

Вы также можете зарегистрировать сервисы через сервис $provide внутри функции config модуля:

angular.module('myModule', []).config(function($provide) {
$provide.factory('serviceId', function() {
  var shinyNewServiceInstance;
  //factory function body that constructs shinyNewServiceInstance
  return shinyNewServiceInstance;
});
});

Этот метод часто используется в модульных тестах для имитации зависимостей сервиса.

Модульное тестирование

Ниже приведен модульный тест для сервиса notify из примера Создание угловых сервисов выше. Пример модульного теста использует шпион Jasmine (мока) вместо реального браузерного alert.

var mock, notify;

beforeEach(function() {
  mock = {alert: jasmine.createSpy()};

  module(function($provide) {
    $provide.value('$window', mock);
  });

  inject(function($injector) {
    notify = $injector.get('notify');
  });
});

it('should not alert first two notifications', function() {
  notify('one');
  notify('two');

  expect(mock.alert).not.toHaveBeenCalled();
});

it('should alert all after third notification', function() {
  notify('one');
  notify('two');
  notify('three');

  expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
});

it('should clear messages after alert', function() {
  notify('one');
  notify('two');
  notify('third');
  notify('more');
  notify('two');
  notify('third');

  expect(mock.alert.callCount).toEqual(2);
  expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
});

Связанные темы

  • Инъекция зависимостей в AngularJS

Связанный API

  • API сервисов Angular
  • API инжектора

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.2.32/docs/guide/services

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API