Myślę, że odpowiedzi są prawidłowe, ale myślę, że czegoś brakuje.
To, czego brakuje, to „dlaczego i co rozwiązuje?”.
Ok zaczynajmy.
Najpierw wspomnijmy o kilku informacjach:
Wszystkie moduły mają dostęp do usług root.
Więc nawet leniwie ładowane moduły mogą korzystać z usługi dostarczonej w app.module.
Co się stanie, jeśli leniwie ładowany moduł zapewni sobie usługę, którą dostarczył już moduł aplikacji? będą 2 wystąpienia.
To nie jest problem, ale czasami jest .
Jak możemy to rozwiązać? po prostu nie importuj modułu z tym dostawcą do modułów ładowanych z opóźnieniem.
Koniec opowieści.
To ^ miało tylko pokazać, że moduły ładowane z opóźnieniem mają swój własny punkt wstrzykiwania (w przeciwieństwie do modułów ładowanych z opóźnieniem).
Ale co się stanie, gdy udostępniony (!) Moduł zadeklaruje providers, a ten moduł zostanie zaimportowany przez lazy i app.module ? Znowu, jak powiedzieliśmy, dwa przypadki.
Jak więc możemy rozwiązać ten problem we współdzielonym module POV? Potrzebujemy sposobu, aby nie używać providers:[]! Czemu? ponieważ zostaną one automatycznie zaimportowane zarówno do zużywającego lazy, jak i do modułu app.module, a nie chcemy tego, ponieważ widzieliśmy, że każdy będzie miał inną instancję.
Cóż, okazuje się, że możemy zadeklarować współdzielony moduł, który nie będzie miał providers:[], ale nadal będzie dostarczał dostawców (przepraszam :))
W jaki sposób? Lubię to :

Uwaga, brak dostawców.
Ale
co się stanie teraz, gdy app.module zaimportuje udostępniony moduł z punktem widzenia usługi? NIC.
co się stanie teraz, gdy leniwy moduł zaimportuje moduł współdzielony z POV usługi? NIC.
Wchodzenie do mechanizmu ręcznego poprzez konwencję:
Zauważysz, że dostawcy na zdjęciach mają service1iservice2
To pozwala nam na importowanie service2dla leniwie ładowanych modułów i service1dla nieleniwych modułów. ( kaszel ... router ... kaszel )
BTW, nikt nie powstrzymuje Cię przed wywołaniem forRootw leniwym module. ale będziesz mieć 2 instancje, ponieważ app.moduleteż powinieneś to robić - więc nie rób tego w leniwych modułach.
Ponadto - jeśli app.modulewywołuje forRoot(i nikt nie dzwoni forchild) - w porządku, ale iniektor root będzie miał tylko service1. (dostępne dla wszystkich aplikacji)
Dlaczego więc tego potrzebujemy? Powiedziałbym :
Pozwala modułowi współdzielonemu, aby móc podzielić jego różnych dostawców w celu użycia ich z chętnymi modułami i leniwymi modułami - za pośrednictwem forRooti forChildkonwencji. Powtarzam: konwencja
Otóż to.
CZEKAJ !! ani słowa o singletonie ?? więc dlaczego wszędzie czytam singletona?
Cóż - jest to ukryte w zdaniu powyżej ^
Pozwala modułowi współdzielonemu, aby móc podzielić jego różnych dostawców w celu użycia z modułami chętnymi i leniwymi - za pośrednictwem forRoot i forChild .
Konwencja (!!!) pozwala to być pojedyncza - albo dokładniej - jeśli nie będą postępować zgodnie z konwencją - będziesz NIE dostać pojedyncza.
Więc jeśli załadować tylko forRootw app.module , a następnie dostać tylko jedną instancję, bo tylko powinien wezwać forRootgo w app.module.
Swoją drogą - w tym miejscu można o tym zapomnieć forChild. leniwie ładowany moduł nie powinien / nie dzwoni forRoot- więc jesteś bezpieczny w POV singletona.
forRoot i forChild to nie jeden nierozerwalny pakiet - po prostu nie ma sensu wywoływać Roota, który oczywiście będzie ładowany tylko app.module bez możliwości leniwych modułów, ma własne usługi, bez tworzenia nowych usług-które-powinny-być -singel.
Konwencja ta daje fajną możliwość zwaną forChild- konsumować "usługi tylko dla leniwie ładowanych modułów".
Oto wersja demonstracyjna Dostawcy root zwracają liczby dodatnie, moduły ładowane z opóźnieniem dają liczby ujemne.