Мне сложно понять внедрение зависимостей в Angular. Итак, мой вопрос: может ли кто-нибудь объяснить, какие из «типов», например, Controller, Factory, Provider и т. Д., Мы можем вводить в другие, включая другие экземпляры того же «типа»?
На самом деле я ищу эту таблицу, заполненную y / n. Для ячеек с одной и той же строкой / столбцом это означает вставку значения одного «типа» в другой другой с тем же «типом».
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant | | | | | | | | |
| Controller | | | | | | | | |
| Directive | | | | | | | | |
| Factory | | | | | | | | |
| Filter | | | | | | | | |
| Provider | | | | | | | | |
| Service | | | | | | | | |
| Value | | | | | | | | |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
angularjs
dependency-injection
user1527166
источник
источник
Ответы:
Вместо того, чтобы просто заполнить таблицу «да» и «нет» без объяснения причин, я расскажу немного подробнее.
[Примечание, добавленное после завершения: это оказалось ... намного дольше, чем я ожидал. Внизу есть надпись, но я надеюсь, что это окажется информативным.]
[Этот ответ также был добавлен в вики AngularJS: Понимание внедрения зависимостей ]
Провайдер (
$provide
)$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); });
Инжектор (
$injector
)Инжектор отвечает за фактическое создание экземпляров наших сервисов с использованием кода, который мы предоставили
$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) { // WON'T WORK -- greeting is an *instance* of a service. // Only providers for services can be injected in config blocks. });
То , что вы делаете иметь доступ к любым поставщикам за услуги , которые вы сделали:
myMod.config(function(greetingProvider) { // a-ok! });
Есть одно важное исключение:
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/
Контроллеры (
$controller
)Функции контроллера можно вводить, но сами контроллеры нельзя вводить в другие объекты. Это потому, что контроллеры не создаются через провайдера. Вместо этого есть встроенная служба 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
различий , перечисленных в данном описании).источник
То, что BinaryMuse делает в своем удивительном ответе о том, что провайдеры, фабрики и услуги - одно и то же, чрезвычайно важно.
Ниже приведено изображение, которое, как мне кажется, может наглядно проиллюстрировать ее точку зрения:
(источник: simplegoodcode.com )
источник
Отличный ответ Мишель. Я просто хочу отметить, что директивы можно вводить. Если у вас есть указанная директива
myThing
, вы можете ввести ее с помощьюmyThingDirective
: Вот надуманный пример .Приведенный выше пример не очень практичен, однако возможность вставки директивы полезна, когда вы хотите украсить эту директиву .
источник