Aber einige Leute haben mich abgemeldet, dass es für sie schwierig ist, DI und seine Fähigkeiten in Angular zu verstehen. Es gibt nicht so viele Materialien im Internet, wie DI effektiv genutzt werden kann, und für viele Entwickler kommt es darauf an, mit globalen Diensten zu arbeiten oder globale Daten vom Stamm der Anwendung an Komponenten zu übergeben.
Schauen wir uns diesen Mechanismus in Angular genauer an.
Kennst du deine Sucht?
Manchmal ist es nicht leicht zu verstehen, wie viele Abhängigkeiten Ihr Code hat.
Schauen Sie sich zum Beispiel diese Pseudoklasse an und zählen Sie, wie viele Abhängigkeiten sie hat:
import { API_URL } from '../../../env/api-url';
import { Logger } from '../../services/logger';
class PseudoClass {
request() {
fetch(API_URL).then(...);
}
onError(error) {
const logger = new Logger();
logger.log(document.location, error);
}
}
Antworten
fetch — API, , , .
API_URL — ( ).
new Logger() — , .
document — API .
API_URL — ( ).
new Logger() — , .
document — API .
Also, was ist falsch?
Beispielsweise ist eine solche Klasse schwer zu testen, da sie von importierten Daten aus anderen Dateien und bestimmten Entitäten in ihnen abhängt.
Eine andere Situation: Dokument und Abruf funktionieren nahtlos in Ihrem Browser. Wenn Sie jedoch eines Tages eine Anwendung an Server Side Rendering übertragen müssen, befinden sich die erforderlichen globalen Variablen möglicherweise nicht in der Umgebung von nodejs.
Was ist DI und warum wird es benötigt?
Abhängigkeitsinjektion verwaltet Abhängigkeiten innerhalb einer Anwendung. Grundsätzlich ist dieses System für uns wie für Angular-Entwickler ziemlich einfach. Es gibt zwei Hauptoperationen: etwas in den Abhängigkeitsbaum einfügen oder etwas daraus abrufen.
Lesen Sie für eine theoretischere Perspektive zu DI das Inversion of Control-Prinzip . Sie können sich auch interessante Videos zum Thema ansehen: eine Reihe von Videos über IoC und DI von Ilya Klimov auf Russisch oder ein kurzes Video über IoC auf Englisch.
Alle Magie kommt von der Reihenfolge, in der wir Abhängigkeiten liefern und nehmen.
So funktionieren Bereiche in DI:
Was können wir in DI setzen?
Die erste DI-Operation besteht darin, etwas hinein zu setzen. Aus diesem Grund können wir mit Angular das Provider-Array in die Dekoratoren unserer Module, Komponenten oder Direktiven schreiben. Mal sehen, woraus dieses Array bestehen kann.
Klasse bereitstellen
Normalerweise weiß das jeder Angular-Entwickler. In diesem Fall fügen Sie Ihrer Anwendung einen Dienst hinzu.
Angular erstellt eine Instanz der Klasse, wenn Sie sie zum ersten Mal anfordern. Und mit kantigem 6, können wir nicht schreiben Klassen in der Provider - Array überhaupt, aber sagen , die Klasse selbst , wo in der DI es gehen sollte mit providedIn :
providers: [
{
provide: SomeService,
useClass: SomeService
},
// Angular :
SomeService
]
Werte liefern
Konstante Werte können auch über DI geliefert werden. Dies kann entweder eine einfache Zeichenfolge mit der URL Ihrer API oder eine komplexe Observable mit Daten sein.
Das Bereitstellen von Werten wird normalerweise in Verbindung mit einem InjectionToken implementiert . Dieses Objekt ist der Schlüssel für die DI-Engine. Zuerst sagen Sie: "Ich möchte diese Daten für diesen Schlüssel erhalten." Und später kommst du zu DI und fragst: "Gibt es etwas auf diesem Schlüssel?"
Ein häufiger Fall ist die Weiterleitung globaler Daten aus dem Stammverzeichnis der Anwendung.
Es ist besser, dies sofort in Aktion zu sehen. Schauen wir uns also Stackblitz anhand eines Beispiels an:
Beispiel erweitern
Im Beispiel haben wir also eine Abhängigkeit von DI erhalten, anstatt sie direkt als Konstante aus einer anderen Datei zu importieren. Und warum ist es besser für uns?
- Wir können den Token-Wert auf jeder Ebene im DI-Baum überschreiben, ohne die Komponenten zu ändern, die ihn verwenden.
- Wir können den Wert des Tokens beim Testen mit geeigneten Daten verspotten.
- Die Komponente ist vollständig isoliert und funktioniert unabhängig vom Kontext immer gleich.
Bereitstellung von Fabriken
Meiner Meinung nach ist dies das leistungsstärkste Werkzeug in Angulars Dependency Injection Engine.
Sie können ein Token erstellen, das das Ergebnis des Kombinierens und Konvertierens der Werte anderer Token ist.
Hier ist ein weiterer Stackbitz mit einem detaillierten Beispiel für die Erstellung einer Factory mit einem Stream.
Beispiel erweitern
Es gibt viele Fälle, in denen die Bereitstellung einer Fabrik Zeit spart oder den Code besser lesbar macht. Manchmal fügen wir Abhängigkeiten in Komponenten ein, um sie zu kombinieren oder in ein völlig anderes Format umzuwandeln. Im vorherigen Artikel habe ich mich eingehender mit diesem Problem befasst und einen alternativen Ansatz zur Lösung solcher Situationen aufgezeigt.
Bereitstellen einer vorhandenen Instanz
Kein häufiger Fall, aber diese Option kann ein sehr nützliches Werkzeug sein.
Sie können eine Entität, die bereits erstellt wurde, in das Token einfügen. Funktioniert gut mit forwardRef .
Schauen Sie sich ein anderes Beispiel mit stackblitz mit einer Direktive an, die die Schnittstelle implementiert und ein anderes Token durch useExisting ersetzt. In diesem Beispiel möchten wir den Nur-DI-Token-Wert für die untergeordneten Komponenten des Elements überschreiben, an dem die Direktive hängt. Darüber hinaus kann die Direktive eine beliebige sein - die Hauptsache ist, dass sie die erforderliche Schnittstelle implementiert.
Beispiel erweitern
DI Decorator Tricks
Mit DI-Dekoratoren können Sie DI-Abfragen flexibler gestalten.
Wenn Sie nicht alle vier Dekorateure kennen, empfehle ich, diesen Artikel auf Medium zu lesen . Der Artikel ist in englischer Sprache, aber es gibt sehr coole und verständliche Visualisierungen zu diesem Thema.
Nicht viele Leute wissen auch, dass DI-Dekoratoren im deps-Array verwendet werden können, das die Argumente für die Provider-Factory vorbereitet.
providers: [
{
provide: SOME_TOKEN,
/**
* ,
* [new Decorator(), new Decorator(),..., TOKEN]
* .
*
* ‘null’,
* OPTIONAL_TOKEN
*/
deps: [[new Optional(), OPTIONAL_TOKEN]],
useFactory: someTokenFactory
}
]
Token Factory
Der InjectionToken-Konstruktor akzeptiert zwei Argumente.
Das zweite Argument ist ein Objekt mit einer Token-Konfiguration.
Eine Token-Factory ist eine Funktion, die aufgerufen wird, sobald jemand dieses Token zum ersten Mal anfordert. Darin können Sie einen bestimmten Standardwert für das Token berechnen oder sogar über die Inject-Funktion auf andere DI-Entitäten zugreifen.
Schauen Sie sich ein Beispiel für die Implementierung der Button-Click-Stream-Funktionalität an, diesmal jedoch in der Token-Factory.
Beispiel erweitern
Fazit
DI in Angular ist ein erstaunliches Thema: Auf den ersten Blick gibt es nicht viele verschiedene Hebel und Werkzeuge zum Lernen, aber Sie können stundenlang über die Möglichkeiten und Verwendungsmöglichkeiten schreiben und sprechen, die sie uns bieten.
Ich hoffe, dieser Artikel hat Ihnen eine Grundlage gegeben, auf der Sie Ihre eigenen Lösungen finden können, um die Arbeit mit Daten in Ihren Anwendungen und Bibliotheken zu vereinfachen.