Ich habe gelesen, dass beim Injizieren beim Bootstrapping alle untergeordneten Elemente dieselbe Instanz verwenden sollten, aber meine Haupt- und Header-Komponenten (Haupt-App enthält Header-Komponente und Router-Outlet) erhalten jeweils eine separate Instanz meiner Dienste.
Ich habe einen FacebookService, mit dem ich die Facebook-Javascript-API anrufe, und einen UserService, der den FacebookService verwendet. Hier ist mein Bootstrap:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);
Aus meiner Protokollierung geht hervor, dass der Bootstrap-Aufruf beendet ist. Dann wird der FacebookService und dann der UserService erstellt, bevor der Code in jedem der Konstruktoren ausgeführt wird, die MainAppComponent, die HeaderComponent und die DefaultComponent:
angular
typescript
angular2-routing
angular2-services
Jason Goemaat
quelle
quelle
UserService
undFacebookService
zuproviders
anderswo?Antworten:
Jason hat vollkommen recht! Dies wird durch die Funktionsweise der Abhängigkeitsinjektion verursacht. Es basiert auf hierarchischen Injektoren.
In einer Angular2-Anwendung gibt es mehrere Injektoren:
Wenn Angular2 versucht, etwas in den Komponentenkonstruktor einzufügen:
Wenn Sie also einen Singleton für die gesamte Anwendung haben möchten, muss der Anbieter entweder auf der Ebene des Root-Injektors oder des Injektors der Anwendungskomponente definiert sein.
Aber Angular2 wird den Injektorbaum von unten betrachten. Dies bedeutet, dass der Anbieter auf der untersten Ebene verwendet wird und der Bereich der zugeordneten Instanz diese Ebene ist.
Siehe diese Frage für weitere Details:
quelle
Update (Winkel 6 +)
Die empfohlene Methode zum Erstellen eines Singleton-Dienstes wurde geändert. Es wird jetzt empfohlen, im
@Injectable
Dekorator des Dienstes anzugeben, dass er im 'root' bereitgestellt werden soll. Dies ist für mich sehr sinnvoll und es besteht keine Notwendigkeit mehr, alle bereitgestellten Dienste in Ihren Modulen aufzulisten. Sie importieren die Dienste nur dann, wenn Sie sie benötigen, und sie registrieren sich an der richtigen Stelle. Sie können auch ein Modul angeben, damit es nur bereitgestellt wird, wenn das Modul importiert wird.Update (Winkel 2)
Mit NgModule besteht die Möglichkeit, dies jetzt zu tun, darin, ein 'CoreModule' mit Ihrer Serviceklasse darin zu erstellen und den Service bei den Anbietern des Moduls aufzulisten. Anschließend importieren Sie das Kernmodul in Ihr Haupt-App-Modul, das allen Kindern, die diese Klasse in ihren Konstruktoren anfordern, die eine Instanz bereitstellt:
CoreModule.ts
AppModule.ts
Ursprüngliche Antwort
Wenn Sie einen Anbieter in auflisten
bootstrap()
, müssen Sie ihn nicht in Ihrem Komponentendekorator auflisten:Wenn Sie Ihre Klasse in "Provider" auflisten, wird eine neue Instanz davon erstellt. Wenn eine übergeordnete Komponente sie bereits auflistet, müssen die untergeordneten Komponenten dies nicht tun. In diesem Fall erhalten sie eine neue Instanz.
quelle
[providers]
in Ihrer Moduldatei auflisten, nicht inbootstrap()
, oder?ApiService
inAppModule
‚sproviders
und damit die Notwendigkeit vermeidenCoreModule
? (Ich bin mir nicht sicher, ob @JasonSwett dies vorschlägt.)ApiService
das oben importieren, aber warum sollten wir uns dann überhaupt die Mühe machen, es in das Provider-Array des CoreModule zu stellen und dieses dann in app.module zu importieren ... es hat für mich noch nicht geklickt.TestService
Instanzen für die Module nicht erstellt werden , obwohl sie sowohl in den Kern- als auch in den App-Modulen angegeben sind, da sie von der Komponente bereitgestellt werden, sodass der Winkel im Injektorbaum nie so hoch ist. Wenn Sie also einen Dienst in Ihrem Modul bereitstellen und ihn niemals verwenden, scheint keine Instanz erstellt zu werden.Ich weiß, dass Angular hierarchische Injektoren hat, wie Thierry sagte.
Aber ich habe hier eine andere Option, falls Sie einen Anwendungsfall finden, bei dem Sie ihn dem Elternteil nicht wirklich injizieren möchten.
Wir können dies erreichen, indem wir eine Instanz des Dienstes erstellen und diese bei Bereitstellung immer zurückgeben.
Und dann verwenden Sie für Ihre Komponente Ihre benutzerdefinierte Bereitstellungsmethode.
Und Sie sollten einen Singleton-Service haben, ohne von den hierarchischen Injektoren abhängig zu sein.
Ich sage nicht, dass dies ein besserer Weg ist, nur für den Fall, dass jemand ein Problem hat, bei dem hierarchische Injektoren nicht möglich sind.
quelle
SHARE_SERVICE_PROVIDER
seinYOUR_SERVICE_PROVIDER
in der Komponente? Außerdem gehe ich davon aus, dass der Import der Servicedatei wie gewohnt erforderlich ist und der Konstruktor weiterhin einen Parameter vom Typ 'YourService' hat, oder? Ich denke, das gefällt mir, ermöglicht es Ihnen, einen Singleton zu garantieren und muss nicht sicherstellen, dass der Dienst in der Hierarchie bereitgestellt wird. Es ermöglicht auch einzelnen Komponenten, ihre eigene Kopie zu erhalten, indem nur der Dienstproviders
anstelle des Singleton-Anbieters aufgelistet wird, oder?YOUR_SERVICE_PROVIDER
. Ja, alle Komponenten erhalten dieselbe Instanz, indem sie nur den Anbietern hinzugefügt werden.instance
Eigenschaft einfach in eine Schlüsselwertzuordnung von InstanzenDie Syntax wurde geändert. Überprüfen Sie diesen Link
Abhängigkeiten sind Singletons im Rahmen eines Injektors. Im folgenden Beispiel wird eine einzelne HeroService-Instanz von der HeroesComponent und ihren untergeordneten HeroListComponent-Instanzen gemeinsam genutzt.
Schritt 1. Erstellen Sie eine Singleton-Klasse mit @Injectable Decorator
Schritt 2. In den Konstruktor injizieren
Schritt 3. Anbieter registrieren
quelle
Injectable
Klasse kein Dienst ist und nurstatic
Zeichenfolgen für den globalen Gebrauch enthält?A
singleton service
ist ein Dienst, für den in einer App nur eine Instanz vorhanden ist.Es gibt (2) Möglichkeiten , einen Singleton-Dienst für Ihre Anwendung bereitzustellen.
Verwenden Sie die
providedIn
Eigenschaft, oderStellen Sie das Modul direkt in
AppModule
der Anwendung bereitMit zur Verfügung gestelltIn
Ab Angular 6.0 besteht die bevorzugte Methode zum Erstellen eines Singleton-Dienstes darin,
providedIn
im@Injectable()
Decorator des Dienstes als Root festzulegen. Dadurch wird Angular angewiesen, den Dienst im Anwendungsstamm bereitzustellen.Array von NgModule-Anbietern
In Apps, die mit Angular-Versionen vor 6.0 erstellt wurden, werden Dienste wie folgt als NgModule-Anbieter-Arrays registriert:
Wenn dies
NgModule
der Stamm wäreAppModule
, wäre der UserService ein Singleton und in der gesamten App verfügbar. Obwohl Sie möglicherweise sehen, dass es auf diese Weise codiert ist, ist die Verwendung derprovidedIn
Eigenschaft des@Injectable()
Dekorateurs für den Dienst selbst ab Angular 6.0 vorzuziehen, da dies Ihre Dienste baumschüttelnd macht.quelle
Wenn Sie
@Injectable
dem Service einen Dekorator hinzufügen und ihn als Anbieter im Root-Modul registrieren, wird er zu einem Singleton.quelle
constructor
:import { SomeService } from '../../services/some/some'; @Component({ selector: 'page-selector', templateUrl: 'page.html', }) export class SomePage { constructor( public someService: SomeService ) { }
Das scheint gut für mich zu funktionieren
quelle
Hier ist ein Arbeitsbeispiel mit Angular Version 2.3. Rufen Sie einfach den Konstruktor des Dienstes wie diesen Konstruktor auf (private _userService: UserService). Und es wird ein Singleton für die App erstellt.
user.service.ts
app.component.ts
quelle
Sie können
useValue
in Anbietern verwendenquelle
useValue
ist nicht mit Singleton verwandt. Usevalue dient nur dazu, einen Wert anstelle von aType
(useClass
) zu übergeben, das DI aufruft,new
oderuseFactory
wenn eine Funktion übergeben wird, die den Wert zurückgibt, wenn sie von DI aufgerufen wird. Angular DI verwaltet automatisch eine einzelne Instanz pro Anbieter. Geben Sie es nur einmal an und Sie haben einen Singleton. Entschuldigung, ich muss abstimmen, weil es nur ungültige Informationen sind: - /Von Angular @ 6 können Sie
providedIn
in einemInjectable
.Überprüfen Sie die Dokumente hier
quelle
public static
.Deklarieren Sie Ihren Dienst einfach nur in app.module.ts als Anbieter.
Es hat den Job für mich gemacht.
dann instanziieren Sie es entweder mit einem privaten Konstruktorparameter:
oder da, wenn Ihr Dienst von HTML verwendet wird, die Option -prod Folgendes beansprucht:
Fügen Sie ein Mitglied für Ihren Dienst hinzu und füllen Sie es mit der im Konstruktor empfangenen Instanz:
quelle
Wenn Sie Service Singleton auf Anwendungsebene erstellen möchten, sollten Sie es in app.module.ts definieren
Anbieter: [MyApplicationService] (Sie können dasselbe auch im untergeordneten Modul definieren, um es modulspezifisch zu machen.)
Wenn Sie einen Singleton-Service auf Komponentenebene definieren möchten, fügen Sie diesen Service in app.module.ts hinzu und fügen Sie das Provider-Array innerhalb einer bestimmten Komponente hinzu, wie im folgenden Snipet gezeigt.
@Component ({Selektor: 'app-root', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], Anbieter: [TestMyService]})
Angular 6 bietet eine neue Möglichkeit, Dienste auf Anwendungsebene hinzuzufügen. Anstatt dem Array "provider []" in AppModule eine Serviceklasse hinzuzufügen, können Sie in @Injectable () die folgende Konfiguration festlegen:
@Injectable ({vorausgesetztIn: 'root'}) Exportklasse MyService {...}
Die "neue Syntax" bietet jedoch einen Vorteil: Dienste können von Angular (hinter den Kulissen) träge geladen und redundanter Code automatisch entfernt werden. Dies kann zu einer besseren Leistung und Ladegeschwindigkeit führen - obwohl dies nur für größere Dienste und Apps im Allgemeinen gilt.
quelle
Zusätzlich zu den oben genannten hervorragenden Antworten fehlt möglicherweise noch etwas anderes, wenn sich die Dinge in Ihrem Singleton immer noch nicht als Singleton verhalten. Ich bin auf das Problem gestoßen, als ich eine öffentliche Funktion für den Singleton aufgerufen habe und festgestellt habe, dass die falschen Variablen verwendet wurden. Es stellt sich heraus, dass das Problem darin bestand, dass
this
nicht garantiert wird, dass es für öffentliche Funktionen im Singleton an den Singleton gebunden ist. Dies kann durch Anschluss an die Beratung korrigiert wird hier , wie so:Alternativ können Sie die Klassenmitglieder einfach als
public static
statt deklarierenpublic
, dann spielt der Kontext keine Rolle, aber Sie müssen auf sie zugreifen,SubscriptableService.onServiceRequested$
anstatt die Abhängigkeitsinjektion zu verwenden und über auf sie zuzugreifenthis.subscriptableService.onServiceRequested$
.quelle
Eltern- und Kinderbetreuung
Ich hatte Probleme mit einem Elterndienst und seinem Kind, die verschiedene Instanzen verwendeten. Um die Verwendung einer Instanz zu erzwingen, können Sie das übergeordnete Element in Bezug auf das untergeordnete Element in Ihren App-Modulanbietern aliasisieren. Der Elternteil kann nicht auf die Eigenschaften des Kindes zugreifen, aber für beide Dienste wird dieselbe Instanz verwendet. https://angular.io/guide/dependency-injection-providers#aliased-class-providers
app.module.ts
Dienste, die von Komponenten außerhalb des Anwendungsbereichs Ihrer App-Module verwendet werden
Beim Erstellen einer Bibliothek, die aus einer Komponente und einem Dienst besteht, ist ein Problem aufgetreten, bei dem zwei Instanzen erstellt wurden. Eine von meinem Angular-Projekt und eine von der Komponente in meiner Bibliothek. Die Reparatur:
my -side.component.ts
my-inside.component.ts
my-inside.component.hmtl
quelle