Zamiast tego wypełnić tabelę słowami „tak” i „nie” bez wyjaśnienia, przejdę do bardziej szczegółowych informacji.
[Uwaga, dodane po skończeniu: skończyło się to ... trochę dłużej niż się spodziewałem. Na dole znajduje się tl; dr, ale mam nadzieję, że to okaże się przydatne.]
[Ta odpowiedź została również dodana do wiki AngularJS: Understanding Dependency Injection ]
$provide
Usługa jest odpowiedzialny za mówienie kątowych, jak tworzyć nowe rzeczy do wstrzyknięć; te rzeczy nazywane są usługami . Usługi są definiowane przez rzeczy zwane dostawcami , czyli to, co tworzysz, używając $provide
. Definiowanie dostawcy odbywa się za pomocą provider
metody w $provide
usłudze i można uzyskać dostęp do $provide
usługi, prosząc o wstrzyknięcie jej do funkcji aplikacji config
. Przykładem może być coś takiego:
app.config(function($provide) {
$provide.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
});
Tutaj zdefiniowaliśmy nowego dostawcę usługi o nazwie greeting
; możemy wstrzyknąć zmienną nazwaną greeting
do dowolnej funkcji do wstrzykiwania (jak kontrolery, o tym później), a Angular wywoła funkcję dostawcy $get
w celu zwrócenia nowej instancji usługi. W tym przypadku zostanie wstrzyknięta funkcja, która pobiera name
parametr i alert
komunikat oparty na nazwie. Możemy tego użyć w ten sposób:
app.controller('MainController', function($scope, greeting) {
$scope.onClick = function() {
greeting('Ford Prefect');
};
});
Oto sztuczka. factory
, service
i value
wszystkie są tylko skrótami do definiowania różnych części dostawcy - to znaczy zapewniają sposób definiowania dostawcy bez konieczności wypisywania wszystkich tych rzeczy. Na przykład możesz napisać dokładnie tego samego dostawcę w ten sposób:
app.config(function($provide) {
$provide.factory('greeting', function() {
return function(name) {
alert("Hello, " + name);
};
});
});
Ważne jest, aby to zrozumieć, więc powtórzę: pod maską AngularJS wywołuje dokładnie ten sam kod , który napisaliśmy powyżej ( $provide.provider
wersja) dla nas. Nie ma dosłownie 100% żadnej różnicy w obu wersjach. value
działa tak samo - jeśli cokolwiek byśmy zwrócili z naszej $get
funkcji (czyli naszej factory
funkcji) jest zawsze dokładnie takie samo, możemy napisać jeszcze mniej kodu używając value
. Na przykład, ponieważ zawsze zwracamy tę samą funkcję dla naszej greeting
usługi, możemy ją value
również zdefiniować:
app.config(function($provide) {
$provide.value('greeting', function(name) {
alert("Hello, " + name);
});
});
Ponownie, jest to w 100% identyczne z pozostałymi dwiema metodami, których użyliśmy do zdefiniowania tej funkcji - to tylko sposób na zaoszczędzenie trochę pisania.
Teraz prawdopodobnie zauważyłeś tę irytującą app.config(function($provide) { ... })
rzecz, której używałem. Ponieważ definiowanie nowych dostawców (za pomocą dowolnej z powyższych metod) jest tak powszechne, AngularJS ujawnia $provider
metody bezpośrednio w obiekcie modułu, aby zaoszczędzić jeszcze więcej wpisywania:
var myMod = angular.module('myModule', []);
myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);
Wszystkie robią to samo, co bardziej szczegółowe app.config(...)
wersje, których używaliśmy wcześniej.
Jedyny wstrzykiwany, który dotychczas pominąłem, to constant
. Na razie łatwo powiedzieć, że działa tak samo value
. Później zobaczymy jedną różnicę.
Aby przejrzeć , wszystkie te fragmenty kodu robią dokładnie to samo:
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);
});
Wtryskiwacz jest odpowiedzialny za faktyczne tworzenie wystąpień naszych usług przy użyciu dostarczonego przez nas kodu $provide
(gra słów nie jest przeznaczona). Za każdym razem, gdy piszesz funkcję, która przyjmuje wstrzyknięte argumenty, widzisz, jak działa wtryskiwacz. Każda aplikacja AngularJS ma jedną, $injector
która jest tworzona podczas pierwszego uruchomienia aplikacji; możesz go zdobyć, wstrzykując $injector
do dowolnej funkcji do wstrzykiwania (tak, $injector
wie, jak wstrzyknąć się!)
Gdy już to zrobisz $injector
, możesz uzyskać wystąpienie określonej usługi, wywołując get
ją z nazwą usługi. Na przykład,
var greeting = $injector.get('greeting');
greeting('Ford Prefect');
Wtryskiwacz jest również odpowiedzialny za wstrzykiwanie usług do funkcji; na przykład, możesz magicznie wstrzyknąć usługi do dowolnej funkcji, którą posiadasz, używając metody wtryskiwacza invoke
;
var myFunction = function(greeting) {
greeting('Ford Prefect');
};
$injector.invoke(myFunction);
Warto zauważyć, że wtryskiwacz utworzy instancję usługi tylko raz . Następnie buforuje wszystko, co zwraca dostawca według nazwy usługi; następnym razem, gdy poprosisz o usługę, otrzymasz dokładnie ten sam przedmiot.
Tak więc, aby odpowiedzieć na twoje pytanie, możesz wstrzyknąć usługi do dowolnej funkcji, która jest wywoływana with$injector.invoke
. To zawiera
- funkcje definicji kontrolera
- funkcje definicji dyrektywy
- funkcje definicji filtrów
- te
$get
metody dostawców (aka factory
funkcji definicji)
Ponieważ constant
s i value
s zawsze zwracają wartość statyczną, nie są wywoływane przez wtryskiwacz, a zatem nie można im nic wstrzyknąć.
Konfigurowanie dostawców
Być może zastanawiasz się, dlaczego ktoś miałby przejmować założyć pełnoprawnym operatorem z provide
metodą jeśli factory
, value
itp są o wiele łatwiejsze. Odpowiedź jest taka, że dostawcy pozwalają na wiele konfiguracji. Wspomnieliśmy już, że kiedy tworzysz usługę za pośrednictwem dostawcy (lub dowolnego skrótu, który daje Ci Angular), tworzysz nowego dostawcę, który definiuje sposób konstruowania tej usługi. Co mogę nie wspomnieć, że tych dostawców może być wstrzyknięty do config
sekcji aplikacji, więc można wchodzić w interakcje z nimi!
Po pierwsze, Angular uruchamia aplikację w dwóch fazach - fazach config
i run
. config
Fazy, jak widzieliśmy, jest miejsce, gdzie można skonfigurować żadnych dostawców, jak to konieczne. Tutaj również konfigurowane są dyrektywy, kontrolery, filtry i tym podobne. run
Fazy, jak można się domyślać, gdzie jest rzeczywiście kątowa kompiluje swój DOM i uruchamia aplikację.
Możesz dodać dodatkowy kod do uruchomienia w tych fazach za pomocą funkcji myMod.config
i myMod.run
- każda z nich przyjmuje funkcję do uruchomienia w tej określonej fazie. Jak widzieliśmy w pierwszej sekcji, funkcje te można wstrzykiwać - wstrzyknęliśmy wbudowaną $provide
usługę w naszym pierwszym przykładzie kodu. Warto jednak zauważyć, że na config
etapie wstrzyknięcia mogą być tylko dostawcy (z wyjątkiem usług w AUTO
module - $provide
i $injector
).
Na przykład niedozwolone jest :
myMod.config(function(greeting) {
// WON'T WORK -- greeting is an *instance* of a service.
// Only providers for services can be injected in config blocks.
});
Co zrobić mają dostępu do jakichkolwiek dostawców za usługi już wykonane:
myMod.config(function(greetingProvider) {
// a-ok!
});
Jest jeden ważny wyjątek: constant
s, ponieważ nie można ich zmienić, mogą być wstrzykiwane do config
bloków (w ten sposób różnią się od value
s). Dostęp do nich uzyskuje się za pomocą samej nazwy ( Provider
przyrostek nie jest wymagany).
Za każdym razem, gdy definiujesz dostawcę usługi, ten dostawca jest nazywany serviceProvider
, gdzie service
jest nazwa usługi. Teraz możemy wykorzystać moc dostawców do robienia bardziej skomplikowanych rzeczy!
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');
});
Teraz mamy funkcję naszego dostawcy o nazwie setText
, której możemy użyć do dostosowania naszego alert
; możemy uzyskać dostęp do tego dostawcy w config
bloku, aby wywołać tę metodę i dostosować usługę. Kiedy w końcu uruchomimy naszą aplikację, możemy pobrać greeting
usługę i wypróbować ją, aby zobaczyć, czy nasze dostosowanie przyniosło skutek.
Ponieważ jest to bardziej złożony przykład, oto działająca demonstracja: http://jsfiddle.net/BinaryMuse/9GjYg/
Funkcje kontrolera można wstrzykiwać, ale same kontrolery nie mogą być wstrzykiwane do innych rzeczy. Dzieje się tak, ponieważ kontrolery nie są tworzone przez dostawcę. Zamiast tego istnieje wbudowana usługa Angular o nazwie, $controller
która jest odpowiedzialna za konfigurowanie kontrolerów. Kiedy dzwonisz myMod.controller(...)
, w rzeczywistości uzyskujesz dostęp do dostawcy tej usługi , tak jak w ostatniej sekcji.
Na przykład, gdy zdefiniujesz kontroler w ten sposób:
myMod.controller('MainController', function($scope) {
// ...
});
Tak naprawdę robisz:
myMod.config(function($controllerProvider) {
$controllerProvider.register('MainController', function($scope) {
// ...
});
});
Później, gdy Angular będzie musiał utworzyć wystąpienie twojego kontrolera, używa $controller
usługi (która z kolei używa $injector
do wywołania funkcji kontrolera, więc dostaje również jej zależności).
Filtry i dyrektywy
filter
i directive
działają dokładnie tak samo jak controller
; filter
korzysta z wywołanej usługi $filter
i jej dostawcy $filterProvider
, podczas gdy directive
korzysta z wywołanej usługi $compile
i jej dostawcy $compileProvider
. Niektóre linki:
Jak w innych przykładach myMod.filter
i myMod.directive
są skrótami do konfiguracji tych usług.
Podsumowując, każda funkcja, która zostanie wywołana za pomocą, $injector.invoke
może zostać wstrzyknięta . Obejmuje to z wykresu (ale nie tylko):
- kontroler
- dyrektywa
- fabryka
- filtr
- dostawca
$get
(przy definiowaniu dostawcy jako obiektu)
- funkcja dostawcy (podczas definiowania dostawcy jako funkcji konstruktora)
- usługa
Dostawca tworzy nowe usługi, które można wstrzyknąć do rzeczy . To zawiera:
- stały
- fabryka
- dostawca
- usługa
- wartość
To powiedziawszy, wbudowane usługi, takie jak $controller
i $filter
mogą być wstrzykiwane, i możesz użyć tych usług, aby uzyskać dostęp do nowych filtrów i kontrolerów, które zdefiniowałeś za pomocą tych metod (nawet jeśli rzeczy, które zdefiniowałeś, same nie mogą być wstrzyknięte do rzeczy).
Poza tym każda funkcja wywoływana przez wtryskiwacz może być wstrzykiwana za pomocą dowolnej usługi świadczonej przez dostawcę - nie ma żadnych ograniczeń (poza wymienionymi tutaj config
i run
różnicami).