So führen Sie einen Dienst aus, wenn die App in Angular 2 gestartet wird

96

Ich habe einen Dienst SocketService erstellt, der im Grunde den Socket initialisiert, damit die App den Port abhören kann. Dieser Dienst interagiert auch mit einigen Komponenten.

// socket.service.ts

export class SocketService {
    constructor() {
        // Initializes the socket
    }
    ...
}

Ich weiß, dass der Code im Konstruktor () von SocketService erst ausgeführt wird, wenn eine Komponente SocketService verwendet.

Und normalerweise sieht der Code in app.ts so aus:

// app.ts

import {SocketService} from './socket.service';
...
class App {
    constructor () {}
}
bootstrap(App, [SocketService]);

Ich möchte jedoch, dass dieser Dienst ausgeführt wird, wenn die App gestartet wird. Also habe ich einen Trick gemacht, füge einfach private _socketService: SocketServiceApp's Konstruktor () hinzu. Jetzt sehen die Codes so aus:

// app.ts (neu)

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {}
}
bootstrap(App, [SocketService]);

Jetzt funktioniert es. Das Problem ist manchmal, dass die Codes im Konstruktor () von SocketService ausgeführt werden, manchmal nicht. Wie soll ich das richtig machen? Vielen Dank

Hongbo Miao
quelle
Dieser Leitfaden hat mir geholfen: angular.io/docs/ts/latest/tutorial/…
Marian07

Antworten:

130

Die Antwort von Stuart zeigt in die richtige Richtung, aber es ist nicht einfach, Informationen zu APP_INITIALIZER zu finden. In der Kurzversion können Sie damit den Initialisierungscode ausführen, bevor einer Ihrer anderen Anwendungscodes ausgeführt wird. Ich habe eine Weile gesucht und hier und hier Erklärungen gefunden , die ich zusammenfassen werde, falls sie aus dem Internet verschwinden.

APP_INITIALIZER ist in Winkel / Kern definiert. Sie fügen es so in Ihre app.module.ts ein.

import { APP_INITIALIZER } from '@angular/core';

APP_INITIALIZER ist ein OpaqueToken (oder ein InjectionToken seit Angular 4), das auf den ApplicationInitStatus-Dienst verweist. ApplicationInitStatus ist ein Multi-Provider . Es unterstützt mehrere Abhängigkeiten und Sie können es mehrmals in Ihrer Anbieterliste verwenden. Es wird so verwendet.

@NgModule({
  providers: [
    DictionaryService,
    {
      provide: APP_INITIALIZER,
      useFactory: (ds: DictionaryService) => () => return ds.load(),
      deps: [DictionaryService],
      multi: true
    }]
})
export class AppModule { }

Diese Providerdeklaration weist die ApplicationInitStatus-Klasse an, die DictionaryService.load () -Methode auszuführen. load () gibt ein Versprechen zurück und ApplicationInitStatus blockiert den App-Start, bis das Versprechen aufgelöst wird. Die Funktion load () ist wie folgt definiert.

load(): Promise<any> {
  return this.dataService.getDiscardReasons()
  .toPromise()
  .then(
    data => {
      this.dictionaries.set("DISCARD_REASONS",data);
    }
  )
}

So eingerichtet wird das Wörterbuch zuerst geladen und die anderen Teile der App können sicher davon abhängen.

Bearbeiten: Beachten Sie, dass dies die Vorladezeit für Ihre App um die Dauer der load () -Methode verlängert. Wenn Sie dies vermeiden möchten, können Sie stattdessen einen Resolver auf Ihrer Route verwenden.

GMK
quelle
Vielen Dank dafür ... sehr hilfreich
Gaurav Joshi
5
Dies sollte die akzeptierte Antwort sein. Die aktuelle verschiebt nur eine Codezeile von einem Konstruktor zu einer initMethode. Während Konstruktoren in der Tat so einfach wie möglich gehalten werden sollten, macht dieser Gedanke allein keine richtige Lösung. Verwenden APP_INITIALIZERtut.
JP Ten Berge
Ich denke nicht, dass die ausgewählte Antwort falsch ist, da sie das Problem von OP löst. ABER da ich ein ähnliches Problem bei der Entwicklung einer Bibliothek habe, habe ich eine andere Frage gestellt, bei der diese Antwort perfekt passen würde.
Machado
Der beste Weg zu tun
Renil Babu
58

Verschieben Sie die Logik in Ihrem SocketServiceKonstruktor stattdessen in eine Methode und rufen Sie diese dann im Konstruktor Ihrer Hauptkomponente oder aufngOnInit

SocketService

export class SocketService{
    init(){
        // Startup logic here
    }
}

App

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {
        _socketService.init();
    }
}
bootstrap(App, [SocketService]);
SnareChops
quelle
1
Ich verstehe nicht, was die Logik dahinter ist, Dinge in der Methode anstelle des Konstruktors zu tun. Könnten Sie dies bitte erklären? Was ist der Vorteil, wenn Sie Logik in der Methode ausführen?
Pardeep Jain
1
Ein sauberer Ansatz imho
inoabrian
11
Konstruktoren sollten so einfach wie möglich sein (normalerweise nur Einspritzpunkte). Wenn Sie zusätzliche Logik hinzufügen müssen, verwenden Sie den ngOnInit-Hook.
Sergio
1
Noch eine andere Sache, an die das Team nicht gedacht hat. Je mehr ich an Angular 4 arbeite, desto klarer wird, wie brillant das Aurelia-Framework aufgebaut ist. All diese Möglichkeiten sind sofort verfügbar, indem einfach ein Dekorateur hinzugefügt wird. Diese Leute wissen, was sie tun.
Joel Hernandez
1
@CodyBugstein Das hängt von Ihrem Anwendungsfall ab. Wenn es nur Feuer und Vergessen ist, rufen Sie einfach die asynchrone Methode auf. Wenn Sie auf das Ergebnis warten müssen, können Sie a Promisevon Ihrer init()Methode zurückgeben und dann nach Bedarf verketten. Was auch immer der Fall , es kann getan werden, aber wird wahrscheinlich schwierig sein , und werden Sie bis zu den Details auszuarbeiten. Wenn Sie weitere Hilfe benötigen, können Sie jederzeit eine Frage mit Details zu Ihrem genauen Problem stellen. Die Community hilft Ihnen gerne weiter.
SnareChops
8

Siehe auch APP_INITIALIZER , das beschrieben wird als;

Eine Funktion, die ausgeführt wird, wenn eine Anwendung initialisiert wird.

Stuart Hallows
quelle
1

Versuchen Sie, einen Servicekonstruktor zu erstellen, und rufen Sie ihn dann in ngOnInit () Ihrer Komponente auf.

  • Servicemodul

 export class SocketService {
    constructor() { }
        getData() {
            //your code Logic
        }
}

  • Komponente

export class AppComponent {
    public record;  
    constructor(private SocketService: DataService){ }
    ngOnInit() {        
        this.SocketService.getData()
        .subscribe((data:any[]) => {
            this.record = data;
        });   
  }  
}       

Hoffe das hilft.

Bhushan Gadekar
quelle
1
@ Hongbo möchte, dass der Dienst ausgeführt wird, wenn die App gestartet wird, nicht in einer bestimmten Komponente, die den Dienst verwendet
Jarod Moser
Diese wirklich einfache Antwort hat bei mir funktioniert. Ich liebe einfache Antworten. Vielen Dank.
Aggie Jon von 87