Вместо того, чтобы просто заполнить таблицу «да» и «нет» без объяснения причин, я расскажу немного подробнее.
[Примечание, добавленное после завершения: это оказалось ... намного дольше, чем я ожидал. Внизу есть надпись, но я надеюсь, что это окажется информативным.]
[Этот ответ также был добавлен в вики AngularJS: Понимание внедрения зависимостей ]
$provide
Служба отвечает за рассказ ANGULAR , как создавать новые инъекционные вещи; эти вещи называются услугами . Услуги определяются вещами, называемыми поставщиками , которые вы создаете, когда используете $provide
. Определение поставщика выполняется с помощью provider
метода $provide
службы, и вы можете получить $provide
службу, запросив ее внедрение в config
функцию приложения . Пример может быть примерно таким:
app.config(function($provide) {
$provide.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
});
Здесь мы определили нового поставщика для службы с именем greeting
; мы можем ввести переменную с именем greeting
в любую инъекционную функцию (например, контроллеры, подробнее об этом позже), и Angular вызовет $get
функцию поставщика, чтобы вернуть новый экземпляр службы. В этом случае будет введена функция, которая принимает name
параметр и alert
сообщение на основе имени. Мы могли бы использовать это так:
app.controller('MainController', function($scope, greeting) {
$scope.onClick = function() {
greeting('Ford Prefect');
};
});
Теперь вот трюк. factory
,, service
и value
- это просто ярлыки для определения различных частей поставщика, то есть они предоставляют средства определения поставщика без необходимости вводить все эти данные. Например, вы могли бы написать того же самого провайдера вот так:
app.config(function($provide) {
$provide.factory('greeting', function() {
return function(name) {
alert("Hello, " + name);
};
});
});
Это важно понимать, так что я буду перефразировать: под капотом, AngularJS называет точной такой же код , который мы написали выше (в $provide.provider
версии) для нас. В двух версиях нет буквально 100% разницы. value
работает точно так же - если все, что мы возвращаем из нашей $get
функции (также известной как наша factory
функция), всегда точно так же, мы можем написать еще меньше кода, используя value
. Например, поскольку мы всегда возвращаем одну и ту же функцию для нашей greeting
службы, мы также можем использовать value
для ее определения:
app.config(function($provide) {
$provide.value('greeting', function(name) {
alert("Hello, " + name);
});
});
Опять же, это на 100% идентично двум другим методам, которые мы использовали для определения этой функции - это просто способ сэкономить время на вводе текста.
Вы, наверное, заметили эту надоедливую app.config(function($provide) { ... })
штуку, которую я использовал. Поскольку определение новых поставщиков (с помощью любого из указанных выше методов) настолько распространено, AngularJS предоставляет $provider
методы непосредственно в объекте модуля, чтобы сэкономить еще больше ввода:
var myMod = angular.module('myModule', []);
myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);
Все они делают то же самое, что и более подробные app.config(...)
версии, которые мы использовали ранее.
Единственный инъекционный препарат, который я пока пропустил, - это constant
. На данный момент достаточно легко сказать, что он работает точно так же, как value
. Позже мы увидим одно отличие.
Для обзора , все эти фрагменты кода делают точно то же самое:
myMod.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
myMod.factory('greeting', function() {
return function(name) {
alert("Hello, " + name);
};
});
myMod.value('greeting', function(name) {
alert("Hello, " + name);
});
Инжектор отвечает за фактическое создание экземпляров наших сервисов с использованием кода, который мы предоставили $provide
(без каламбура). Каждый раз, когда вы пишете функцию, которая принимает введенные аргументы, вы видите работу инжектора. Каждое приложение AngularJS имеет одно приложение, $injector
которое создается при первом запуске приложения; вы можете получить его, вводя $injector
в любую инъекционную функцию (да, $injector
знает, как внедрить себя!)
Как только вы это сделаете $injector
, вы можете получить экземпляр определенной службы, вызвав get
ее с именем службы. Например,
var greeting = $injector.get('greeting');
greeting('Ford Prefect');
Инжектор также отвечает за внедрение сервисов в функции; например, вы можете волшебным образом внедрить сервисы в любую имеющуюся у вас функцию, используя метод инжектора invoke
;
var myFunction = function(greeting) {
greeting('Ford Prefect');
};
$injector.invoke(myFunction);
Стоит отметить, что инжектор создает экземпляр службы только один раз . Затем он кэширует все, что поставщик возвращает по имени службы; в следующий раз, когда вы попросите об услуге, вы получите точно такой же объект.
Итак, чтобы ответить на ваш вопрос, вы можете внедрить службы в любую функцию, которая вызывается с помощью$injector.invoke
. Это включает в себя
- функции определения контроллера
- функции определения директивы
- функции определения фильтра
- что
$get
методы провайдеров (иначе factory
функция определения)
Поскольку constant
s и value
s всегда возвращают статическое значение, они не вызываются через инжектор, и поэтому вы не можете вводить их ничем.
Настройка провайдеров
Вы можете быть удивлены , почему кто -то будет беспокоить , чтобы создать полноценный провайдер с provide
методом , если factory
, value
и т.д. так гораздо проще. Ответ заключается в том, что провайдеры допускают множество настроек. Мы уже упоминали, что когда вы создаете службу через поставщика (или любой из ярлыков, которые дает вам Angular), вы создаете нового поставщика, который определяет, как создается эта служба. Я не упомянул, что этих провайдеров можно внедрять в config
разделы вашего приложения, чтобы вы могли с ними взаимодействовать!
Во- первых, Угловое запускает приложение в двух фазах - config
и run
фаз. На config
этапе, как мы видели, вы можете настроить любых поставщиков по мере необходимости. Здесь также настраиваются директивы, контроллеры, фильтры и т.п. На run
этапе, как вы могли догадаться, Angular фактически компилирует вашу DOM и запускает ваше приложение.
Вы можете добавить дополнительный код , который будет работать в этих фазах с myMod.config
и myMod.run
функциями - каждый берет функцию для выполнения на этой конкретной стадии. Как мы видели в первом разделе, эти функции являются инъекционными - мы внедрили встроенную $provide
службу в наш самый первый пример кода. Однако стоит отметить, что на config
этапеAUTO
внедрения могут быть введены только провайдеры (за исключением сервисов в модуле - $provide
и $injector
).
Например, недопустимы :
myMod.config(function(greeting) {
});
То , что вы делаете иметь доступ к любым поставщикам за услуги , которые вы сделали:
myMod.config(function(greetingProvider) {
});
Есть одно важное исключение: constant
s, поскольку они не могут быть изменены, разрешено вводить внутрь config
блоков (этим они отличаются от value
s). Доступ к ним можно получить только по имени ( Provider
суффикс не требуется).
Каждый раз, когда вы определяете поставщика для службы, этот поставщик получает имя serviceProvider
, где service
- имя службы. Теперь мы можем использовать возможности провайдеров для более сложных вещей!
myMod.provider('greeting', function() {
var text = 'Hello, ';
this.setText = function(value) {
text = value;
};
this.$get = function() {
return function(name) {
alert(text + name);
};
};
});
myMod.config(function(greetingProvider) {
greetingProvider.setText("Howdy there, ");
});
myMod.run(function(greeting) {
greeting('Ford Prefect');
});
Теперь у нашего провайдера есть функция, setText
которую мы можем использовать для настройки наших alert
; мы можем получить доступ к этому провайдеру в config
блоке для вызова этого метода и настройки сервиса. Когда мы, наконец, запустим наше приложение, мы можем взять greeting
сервис и попробовать его, чтобы убедиться, что наши настройки вступили в силу.
Поскольку это более сложный пример, вот рабочая демонстрация: http://jsfiddle.net/BinaryMuse/9GjYg/
Функции контроллера можно вводить, но сами контроллеры нельзя вводить в другие объекты. Это потому, что контроллеры не создаются через провайдера. Вместо этого есть встроенная служба Angular, $controller
которая отвечает за настройку ваших контроллеров. Когда вы звоните myMod.controller(...)
, вы фактически обращаетесь к поставщику этой услуги , как и в предыдущем разделе.
Например, когда вы определяете такой контроллер:
myMod.controller('MainController', function($scope) {
});
На самом деле вы делаете следующее:
myMod.config(function($controllerProvider) {
$controllerProvider.register('MainController', function($scope) {
});
});
Позже, когда Angular необходимо создать экземпляр вашего контроллера, он использует $controller
службу (которая, в свою очередь, использует $injector
для вызова функции вашего контроллера, чтобы он также вводил свои зависимости).
Фильтры и директивы
filter
и directive
работать точно так же, как controller
; filter
использует вызываемую службу $filter
и ее поставщика $filterProvider
, в то время как directive
использует вызываемую службу $compile
и ее поставщика $compileProvider
. Некоторые ссылки:
В соответствии с другими примерами, myMod.filter
и myMod.directive
служат для быстрого доступа к настройке этих услуг.
Итак, чтобы подвести итог, можно внедрить любую функцию, которая вызывается с $injector.invoke
помощью . Это включает в себя из вашей диаграммы (но не ограничивается):
- контролер
- директива
- фабрика
- фильтр
- поставщик
$get
(при определении поставщика как объекта)
- функция поставщика (при определении поставщика как функции конструктора)
- оказание услуг
Провайдер создает новые услуги, которые можно внедрять в вещи . Это включает в себя:
- постоянный
- фабрика
- провайдер
- оказание услуг
- значение
Тем не менее, встроенные службы, такие как $controller
и, $filter
могут быть введены, и вы можете использовать эту службу, чтобы получить новые фильтры и контроллеры, которые вы определили с помощью этих методов (даже если вещи, которые вы определили сами по себе, не могут вводится в вещи).
Кроме того, любая функция инжектора-вызываются может быть введена с любым провайдером , предоставляемой службой - нет никаких ограничений (кроме config
и run
различий , перечисленных в данном описании).