
Angular 6 führte eine neue verbesserte Syntax zum Einbetten von Dienstabhängigkeiten in eine Anwendung ein (
requireIn ). Trotz der Tatsache, dass Angular 7 bereits veröffentlicht wurde, ist dieses Thema immer noch relevant.
Die Kommentare von GitHub, Slack und Stack Overflow sind sehr verwirrend. Schauen wir uns dieses Thema also genauer an.
In diesem Artikel werden wir Folgendes berücksichtigen:
- Abhängigkeitsinjektion
- Alte Methode, um Abhängigkeiten in Angular einzufügen ( Anbieter: [] );
- Eine neue Methode zum Einfügen von Abhängigkeiten in Angular ( vorausgesetzt: 'root' | SomeModule );
- UseIn- Szenarien bietenIn ;
- Empfehlungen zur Verwendung der neuen Syntax in Anwendungen;
- Zusammenfassend.
Abhängigkeitsinjektion
Sie können diesen Abschnitt überspringen, wenn Sie bereits eine Vorstellung von
DI haben .
Mit Dependency Injection ( DI ) können Objekte erstellt werden, die von anderen Objekten abhängen. Das Abhängigkeitsinjektionssystem stellt abhängige Objekte bereit, wenn es eine Klasse instanziiert.
- Winkeldokumentation
Formale Erklärungen sind gut, aber schauen wir uns genauer an, was Abhängigkeitsinjektion ist.
Alle Komponenten und Dienste sind Klassen. Jede Klasse verfügt über eine spezielle
Konstruktormethode , die beim Aufruf ein Instanzobjekt dieser Klasse erstellt, das in der Anwendung verwendet wird.
Angenommen, in einem unserer Dienste gibt es den folgenden Code:
constructor(private http: HttpClient)
Wenn Sie es ohne Verwendung des Abhängigkeitsinjektionsmechanismus erstellen, müssen Sie
HttpClient manuell hinzufügen. Dann sieht der Code folgendermaßen aus:
const myService = new MyService(httpClient)
Aber wo in diesem Fall
httpClient bekommen? Es muss auch erstellt werden:
const httpClient = new HttpClient(httpHandler)
Aber wo bekommt
man jetzt
httpHandler ? Und so weiter, bis alle notwendigen Klassen instanziiert sind. Wie wir sehen können, kann die manuelle Erstellung kompliziert sein und dabei können Fehler auftreten.
Der Winkelabhängigkeitsinjektionsmechanismus erledigt dies alles automatisch. Wir müssen lediglich die Abhängigkeiten im Komponentenkonstruktor angeben und sie werden ohne unser Zutun hinzugefügt.Alte Methode zum Einfügen von Abhängigkeiten in Angular (Anbieter: [])
Um die Anwendung ausführen zu können, muss Angular jedes einzelne Objekt kennen, das in Komponenten und Services implementiert werden soll. Vor der Veröffentlichung von Angular 6 bestand die einzige Möglichkeit darin, die Dienste in der
Provider- Eigenschaft anzugeben
: [] decorators
@NgModule ,
@Component und
@Directive .

Hier sind drei Hauptverwendungen von
Anbietern: [] :
- Im @ NgModule- Dekorator des sofort geladenen Moduls ( eifrig );
- Im @ NgModule- Dekorator des Moduls für verzögertes Laden ( faul );
- In Dekorateuren @Component und @Directive .
Mit der Anwendung heruntergeladene Module (Eager)
In diesem Fall wird der Dienst im globalen Bereich als Singleton registriert. Es wird ein Singleton sein, selbst wenn es in
Anbietern [] mehrerer Module enthalten ist. Es wird eine einzelne Instanz der Serviceklasse erstellt, die auf der Stammebene der Anwendung registriert wird.
Verzögerte Lademodule (Lazy)
Während der Initialisierung wird eine Instanz des mit dem
Lazy- Modul verbundenen Dienstes erstellt. Das Hinzufügen eines solchen Dienstes zur
eifrigen Komponente des Moduls führt zu einem Fehler:
Kein Anbieter für MyService! Fehler .
Implementierung in @ Component und @ Directive
Bei der Implementierung in einer Komponente oder Direktive wird eine separate Instanz des Dienstes erstellt, die in dieser Komponente und allen untergeordneten Komponenten verfügbar ist.
In dieser Situation ist der Dienst kein Singleton, seine Instanz wird jedes Mal erstellt, wenn die Komponente verwendet und gelöscht wird, zusammen mit dem Entfernen der Komponente aus dem DOM.
In diesem Fall ist
RandomService nicht auf Modulebene implementiert und kein Singleton.
aber bei
Anbietern registriert
: [] der
RandomComponent- Komponente. Infolgedessen erhalten wir jedes Mal eine neue Zufallszahl, wenn Sie
<randm> </ randm> verwenden .
Neue Methode zum Einfügen von Abhängigkeiten in Angular (vorausgesetzt: 'root' | SomeModule)
In Angular 6 haben wir ein neues Tool
"Tree-Shakable Providers" zum
Einfügen von Abhängigkeiten in eine Anwendung erhalten, das mit der Eigenschaft
"ardsIn " des
@ Injectable- Dekorators verwendet werden kann.
Sie können sich vorausgesetzt als die Implementierung von Abhängigkeiten in die entgegengesetzte Richtung vorstellen: Bevor das Modul die Dienste beschrieb, mit denen es verbunden werden soll, definiert der Dienst nun das Modul, mit dem es verbunden wird.Der Dienst kann in das Stammverzeichnis der Anwendung (
bereitgestellt in: 'root' ) oder in ein beliebiges Modul (
bereitgestellt in: SomeModule )
eingebettet werden .
bereitgestelltIn: 'root' ist eine Abkürzung für die Bereitstellung im
AppModule .

Lassen Sie uns die wichtigsten Szenarien für die Verwendung der neuen Syntax analysieren:
- Implementierung im Root-Modul der Anwendung ( vorausgesetzt: 'root' );
- Implementierung im sofort geladenen Modul ( eifrig );
- Implementierung im Modul mit verzögertem Laden ( faul ).
Implementierung im Root-Modul der Anwendung (vorausgesetztIn: 'root')
Dies ist die häufigste Option zur Abhängigkeitsinjektion. In diesem Fall wird der Dienst nur dann zur Bundle-Anwendung hinzugefügt, wenn er tatsächlich verwendet wird, d. H. eingebettet in eine Komponente oder einen anderen Dienst.
Bei Verwendung des neuen Ansatzes gibt es keinen großen Unterschied in einer monolithischen SPA-Anwendung, in der alle schriftlichen Dienste verwendet werden, jedoch
bereitgestellt. In: 'root' ist beim Schreiben von Bibliotheken hilfreich.
Bisher mussten alle Bibliotheksdienste den
Anbietern hinzugefügt
werden: [] ihres Moduls. Nach dem Importieren der Bibliothek in die Anwendung wurden alle Dienste zum Bundle hinzugefügt, auch wenn nur einer verwendet wurde. Im Fall von
Bereitgestellt in: 'root' muss das Bibliotheksmodul nicht angeschlossen werden. Betten Sie den Service einfach in die gewünschte Komponente ein.
Modul zum verzögerten Laden (faul) und bereitgestelltIn: 'root'
Was passiert, wenn Sie den Dienst mit
deployIn: 'root' im
Lazy- Modul implementieren?
Technisch gesehen steht
'root' für
AppModule , aber Angular ist intelligent genug, um dem
Lazy Bundle eines Moduls einen Service hinzuzufügen, wenn er nur in seinen Komponenten und Services implementiert ist. Es gibt jedoch ein Problem (obwohl einige Leute behaupten, dass dies eine Funktion ist). Wenn Sie später den Dienst, der nur im
Lazy- Modul verwendet wird, in das Hauptmodul einführen, wird der Dienst in das
Hauptpaket übertragen. In großen Anwendungen mit vielen Modulen und Diensten kann dies zu Problemen bei der Abhängigkeitsverfolgung und zu unvorhersehbarem Verhalten führen.
Seien Sie aufmerksam! Die Implementierung eines Dienstes in mehreren Modulen kann zu versteckten Abhängigkeiten führen, die schwer zu verstehen und nicht zu entschlüsseln sind.Glücklicherweise gibt es Möglichkeiten, dies zu verhindern, und wir werden sie im Folgenden betrachten.
Abhängigkeitsinjektion in sofort geladenem Modul (eifrig)
In der Regel ist dieser Fall nicht sinnvoll und stattdessen können wir
vorausgesetzt: 'root' verwenden . Das Verbinden eines Dienstes in
EagerModule kann zur Kapselung verwendet werden und verhindert die Implementierung ohne Anschließen eines Moduls. In den meisten Fällen ist dies jedoch nicht erforderlich.
Wenn Sie den Umfang des Dienstes wirklich einschränken müssen, ist es einfacher, die alte
Provider- Methode zu verwenden
: [] , da dies sicherlich nicht zu zyklischen Abhängigkeiten führt.
Wenn möglich, versuchen Sie in allen eifrigen Modulen die Verwendung von availableIn: 'root'.Hinweis Der Vorteil von verzögerten Lademodulen (faul)
Eines der Hauptmerkmale von Angular ist die Möglichkeit, die Anwendung einfach in Fragmente aufzuteilen, was die folgenden Vorteile bietet:
- Die geringe Größe des Hauptbündels der Anwendung, aufgrund derer die Anwendung schneller geladen und gestartet wird.
- Das Modul für verzögertes Laden ist gut isoliert und wird in der Anwendung einmal in der Eigenschaft loadChildren der entsprechenden Route verbunden.
Dank des verzögerten Ladens kann ein ganzes Modul mit Hunderten von Diensten und Komponenten ohne großen Aufwand entfernt oder in eine separate Anwendung oder Bibliothek verschoben werden.Ein weiterer Vorteil der Isolierung des
Lazy- Moduls besteht darin, dass ein darin gemachter Fehler den Rest der Anwendung nicht beeinträchtigt. Jetzt können Sie auch am Veröffentlichungstag ruhig schlafen.
Implementierung in einem Modul mit verzögertem Laden (vorausgesetzt: LazyModule)

Die Abhängigkeitsinjektion in ein bestimmtes Modul verhindert die Verwendung des Dienstes in anderen Teilen der Anwendung. Dadurch bleibt die Abhängigkeitsstruktur erhalten, was besonders für große Anwendungen nützlich ist, bei denen eine unordentliche Abhängigkeitsinjektion zu Verwirrung führen kann.
Interessante Tatsache: Wenn Sie den Lazy Service im Hauptteil der Anwendung implementieren, schlägt die Assembly (auch AOT) fehlerfrei fehl, die Anwendung stürzt jedoch mit dem Fehler "Kein Anbieter für LazyService" ab.Das Problem mit der zyklischen Abhängigkeit

Sie können den Fehler wie folgt reproduzieren:
- Erstellen Sie das LazyModule- Modul.
- Wir erstellen den LazyService- Dienst und stellen eine Verbindung mit bereitgestellten Informationen her: LazyModule ;
- Wir erstellen die LazyComponent- Komponente und verbinden sie mit dem LazyModule .
- Fügen Sie LazyService zum Konstruktor der LazyComponent- Komponente hinzu.
- Wir erhalten einen Fehler mit einer zyklischen Abhängigkeit.
Schematisch sieht es so aus:
Service -> Modul -> Komponente -> Service .
Sie können dieses Problem lösen, indem Sie ein Submodul
LazyServiceModule erstellen , das mit
LazyModule verbunden wird . Verbinden Sie Dienste mit dem Submodul.

In diesem Fall müssen Sie ein zusätzliches Modul erstellen, dies erfordert jedoch keinen großen Aufwand und bietet die folgenden Vorteile:
- Dadurch wird die Einführung des Dienstes in anderen Anwendungsmodulen verhindert.
- Ein Dienst wird dem Bundle nur hinzugefügt, wenn er in eine Komponente oder einen anderen im Modul verwendeten Dienst eingebettet ist.
Einbetten eines Dienstes in eine Komponente (bereitgestellt in: SomeComponent)
Ist es möglich, einen Dienst mit der neuen Syntax in
@Component oder
@Directive einzubetten?
Im Moment nicht!Um eine Instanz des Dienstes für jede Komponente zu erstellen, müssen Sie weiterhin
Anbieter verwenden: [] in den
Dekoratoren @ omponent oder
@Directive .

Best Practices für die Verwendung neuer Syntax in Anwendungen
Bibliotheken
vorausgesetzt: 'root' eignet sich zum Erstellen von Bibliotheken. Dies ist eine sehr bequeme Möglichkeit, nur den direkt verwendeten Teil der Funktionalität mit der Hauptanwendung zu verbinden und die Größe der Endmontage zu reduzieren.
Ein praktisches Beispiel ist die ngx-Modellbibliothek , die mit der neuen Syntax neu geschrieben wurde und jetzt @ angle-extensions / model heißt . In der neuen Implementierung muss NgxModelModule nicht mit der Anwendung verbunden werden. Es reicht aus, ModelFactory nur in die erforderliche Komponente einzubetten. Details zur Implementierung finden Sie hier .Aufgeschobene Download-Module (faul)
Verwenden Sie das separate Modul
ProvidedIn: LazyServicesModule für Dienste und schließen Sie es an
LazyModule an . Dieser Ansatz kapselt Dienste und verhindert, dass sie in andere Module eingesteckt werden. Dadurch werden Grenzen gesetzt und eine skalierbare Architektur erstellt.
Nach meiner Erfahrung kann eine versehentliche Einführung in das Haupt- oder Zusatzmodul (unter Verwendung von Bereitgestelltem: 'root') zu Verwirrung führen und ist nicht die beste Lösung!Bereitgestellt in: 'root' funktioniert auch korrekt, aber bei Verwendung von
Bereitgestellt: LazyServideModule wird bei der Implementierung in anderen Modulen ein Fehler
"Fehlender Anbieter" angezeigt , und wir können die Architektur beheben.
Verschieben Sie den Dienst an einen geeigneteren Ort im Hauptteil der Anwendung.Wann sollten Anbieter eingesetzt werden: []?
In Fällen, in denen das Modul konfiguriert werden muss. Verbinden Sie den Dienst beispielsweise nur mit
SomeModule.forRoot (someConfig) .
Andererseits können Sie in dieser Situation vorausgesetzt: 'root' verwenden. Dadurch wird garantiert, dass der Dienst nur einmal zur Anwendung hinzugefügt wird.Schlussfolgerungen
- Verwenden Sie availableIn : 'root' , um den Dienst als Singleton zu registrieren, der in der gesamten Anwendung verfügbar ist.
- Verwenden Sie für das im Hauptpaket enthaltene Modul Bereitgestellt in: 'root' , nicht Bereitgestellt in: EagerlyImportedModule . Verwenden Sie in Ausnahmefällen Anbieter: [] zur Kapselung.
- Erstellen Sie ein Submodul mit Diensten, um deren Umfang einzuschränken. In: LazyServiceModule bei Verwendung des verzögerten Ladens.
- Stecken Sie das LazyServiceModule- Modul in das LazyModule , um eine zirkuläre Abhängigkeit zu vermeiden.
- Verwenden Sie Anbieter: [] in den Dekoratoren @ omponent und @Directive , um für jede neue Komponenteninstanz eine neue Dienstinstanz zu erstellen. Eine Dienstinstanz ist auch in allen untergeordneten Komponenten verfügbar.
- Begrenzen Sie immer den Umfang der Abhängigkeiten, um die Architektur zu verbessern und verwirrende Abhängigkeiten zu vermeiden.
Referenzen
Originalartikel.Angular ist eine russischsprachige Gemeinschaft.Angular Meetups in Russland