Mam trochę trudności ze zrozumieniem Dependency Injection w Angular. Więc moje pytanie brzmi: czy ktokolwiek może wyjaśnić, które z „typów”, takich jak kontroler, fabryka, dostawca itp., Możemy wstrzyknąć do innych, w tym do innych instancji tego samego „typu”?
To, czego właściwie szukam, to ta tabela wypełniona t / n. W przypadku komórek z tym samym wierszem / kolumną oznacza to wstawienie wartości jednego „typu” do innego o tym samym „typie”
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant | | | | | | | | |
| Controller | | | | | | | | |
| Directive | | | | | | | | |
| Factory | | | | | | | | |
| Filter | | | | | | | | |
| Provider | | | | | | | | |
| Service | | | | | | | | |
| Value | | | | | | | | |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
angularjs
dependency-injection
user1527166
źródło
źródło
Odpowiedzi:
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 ]
Dostawca (
$provide
)$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 aplikacjiconfig
. Przykładem może być coś takiego: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 pobieraname
parametr ialert
komunikat oparty na nazwie. Możemy tego użyć w ten sposób:Oto sztuczka.
factory
,service
ivalue
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: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 naszejfactory
funkcji) jest zawsze dokładnie takie samo, możemy napisać jeszcze mniej kodu używającvalue
. Na przykład, ponieważ zawsze zwracamy tę samą funkcję dla naszejgreeting
usługi, możemy jąvalue
również zdefiniować: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: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 samovalue
. Później zobaczymy jedną różnicę.Aby przejrzeć , wszystkie te fragmenty kodu robią dokładnie to samo:
Wtryskiwacz (
$injector
)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ącget
ją z nazwą usługi. Na przykład,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
;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$get
metody dostawców (akafactory
funkcji definicji)Ponieważ
constant
s ivalue
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ślifactory
,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 doconfig
sekcji aplikacji, więc można wchodzić w interakcje z nimi!Po pierwsze, Angular uruchamia aplikację w dwóch fazach - fazach
config
irun
.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
imyMod.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 naconfig
etapie wstrzyknięcia mogą być tylko dostawcy (z wyjątkiem usług wAUTO
module -$provide
i$injector
).Na przykład niedozwolone jest :
Co zrobić mają dostępu do jakichkolwiek dostawców za usługi już wykonane:
Jest jeden ważny wyjątek:
constant
s, ponieważ nie można ich zmienić, mogą być wstrzykiwane doconfig
bloków (w ten sposób różnią się odvalue
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
, gdzieservice
jest nazwa usługi. Teraz możemy wykorzystać moc dostawców do robienia bardziej skomplikowanych rzeczy!Teraz mamy funkcję naszego dostawcy o nazwie
setText
, której możemy użyć do dostosowania naszegoalert
; możemy uzyskać dostęp do tego dostawcy wconfig
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/
Kontrolery (
$controller
)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 dzwoniszmyMod.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:
Tak naprawdę robisz:
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
idirective
działają dokładnie tak samo jakcontroller
;filter
korzysta z wywołanej usługi$filter
i jej dostawcy$filterProvider
, podczas gdydirective
korzysta z wywołanej usługi$compile
i jej dostawcy$compileProvider
. Niektóre linki:Jak w innych przykładach
myMod.filter
imyMod.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):$get
(przy definiowaniu dostawcy jako obiektu)Dostawca tworzy nowe usługi, które można wstrzyknąć do rzeczy . To zawiera:
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
irun
różnicami).źródło
Kwestia, którą BinaryMuse czyni w swojej niesamowitej odpowiedzi na temat dostawców, fabryk i usług, są niezwykle ważne.
Poniżej znajduje się obraz, który moim zdaniem może wizualnie zilustrować jej punkt widzenia:
(źródło: Simplygoodcode.com )
źródło
Świetna odpowiedź Michelle. Chcę tylko zaznaczyć, że dyrektywy można wstrzyknąć. Jeśli masz dyrektywę o nazwie
myThing
, możesz ją wstrzyknąćmyThingDirective
: Oto wymyślony przykład .Powyższy przykład nie jest zbyt praktyczny, jednak możliwość wstrzyknięcia dyrektywy jest przydatna, gdy chcesz ją ozdobić .
źródło