Jak uruchomić usługę, gdy aplikacja uruchamia się w Angular 2

99

Stworzyłem usługę SocketService, w zasadzie inicjalizuje gniazdo, aby aplikacja nasłuchiwała na porcie. Ta usługa współdziała również z niektórymi komponentami.

// socket.service.ts

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

Wiem, że kod w konstruktorze SocketService () zaczyna działać tylko wtedy, gdy składnik używa SocketService.

Zwykle kod w app.ts wygląda tak:

// app.ts

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

Jednak chcę, aby ta usługa działała podczas uruchamiania aplikacji. Zrobiłem więc sztuczkę, po prostu private _socketService: SocketServicedodałem konstruktor aplikacji (). Więc teraz kody wyglądają tak:

// app.ts (nowy)

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

Teraz działa. Problem polega na tym, że czasami kody w konstruktorze () SocketService działają, czasami nie. Jak więc mam to zrobić poprawnie? Dzięki

Hongbo Miao
źródło
Ten przewodnik mi pomógł: angular.io/docs/ts/latest/tutorial/…
Marian07

Odpowiedzi:

135

Odpowiedź Stuarta wskazuje we właściwym kierunku, ale nie jest łatwo znaleźć informacje w APP_INITIALIZER. Krótka wersja polega na tym, że można go użyć do uruchomienia kodu inicjującego przed uruchomieniem jakiegokolwiek innego kodu aplikacji. Szukałem przez chwilę i znalazłem wyjaśnienia tutaj i tutaj , które podsumuję na wypadek, gdyby zniknęły z sieci.

APP_INITIALIZER jest zdefiniowany w angular / core. Umieszczasz go w swoim app.module.ts w ten sposób.

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

APP_INITIALIZER to OpaqueToken (lub InjectionToken od Angular 4), który odwołuje się do usługi ApplicationInitStatus. ApplicationInitStatus to wielu dostawców . Obsługuje wiele zależności i możesz go wielokrotnie używać na liście dostawców. Jest używany w ten sposób.

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

Ta deklaracja dostawcy nakazuje klasie ApplicationInitStatus uruchomienie metody DictionaryService.load (). load () zwraca obietnicę, a ApplicationInitStatus blokuje uruchamianie aplikacji, dopóki obietnica nie zostanie rozwiązana. Funkcja load () jest zdefiniowana w ten sposób.

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

Skonfiguruj w ten sposób, że słownik jest ładowany jako pierwszy, a inne części aplikacji mogą bezpiecznie na nim polegać.

Edycja: należy pamiętać, że spowoduje to wydłużenie czasu wczytywania aplikacji z góry o tyle, ile zajmie metoda load (). Jeśli chcesz tego uniknąć, możesz zamiast tego użyć resolvera na trasie.

GMK
źródło
Dziękuję za to ... bardzo pomocne
Gaurav Joshi
5
To powinna być akceptowana odpowiedź. Bieżąca przenosi tylko jedną linię kodu z konstruktora do initmetody. Chociaż konstruktorzy rzeczywiście powinni być tak proste, jak to tylko możliwe, sama ta myśl nie sprawia, że ​​jest to właściwe rozwiązanie. Używanie APP_INITIALIZERnie.
JP ten Berge
Nie sądzę, aby wybrana odpowiedź była błędna, ponieważ rozwiązuje problem OP. ALE , ponieważ mam podobny problem z rozwojem niektórych bibliotek, otworzyłem kolejne pytanie, w którym ta odpowiedź pasowałaby idealnie.
Machado
Najlepszy sposób
Renil Babu
58

SocketServiceZamiast tego przenieś logikę w konstruktorze do metody, a następnie wywołaj ją w konstruktorze lubngOnInit

SocketService

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

Aplikacja

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {
        _socketService.init();
    }
}
bootstrap(App, [SocketService]);
SnareChops
źródło
1
nie rozumiem, jaka logika stoi za zrobieniem rzeczy w metodzie zamiast w konstruktorze, czy mógłbyś to wyjaśnić, jaka jest korzyść z robienia logiki w metodzie?
Pardeep Jain
1
Czystsze podejście
imho
12
Konstruktory powinny być tak proste, jak to tylko możliwe (zwykle tylko punkty wtrysku), w przypadku, gdy musisz dodać dodatkową logikę, użyj haka ngOnInit.
Sergio
1
Jeszcze jedna rzecz, o której zespół nie pomyślał. Im dłużej pracuję nad Angular 4, zdaję sobie sprawę, jak genialnie zbudowany jest framework Aurelia. Ma wszystkie te możliwości zaraz po wyjęciu z pudełka, po prostu dodając dekorator. Ci faceci wiedzą, co robią.
Joel Hernandez
1
@CodyBugstein To zależy od twojego przypadku użycia. Jeśli to tylko odpal i zapomnij, po prostu wywołaj metodę asynchroniczną. Jeśli chcesz poczekać na wynik, możesz zwrócić a Promiseze swojej init()metody, a następnie łańcuch w razie potrzeby. W każdym przypadku można to zrobić, ale prawdopodobnie będzie to trudne i ustalenie szczegółów będzie zależało od Ciebie. Jeśli potrzebujesz dalszej pomocy, zawsze możesz zadać pytanie zawierające szczegółowe informacje o Twoim problemie, a społeczność z przyjemnością Ci pomoże.
SnareChops
8

Zobacz także APP_INITIALIZER , opisaną jako;

Funkcja, która zostanie wykonana podczas inicjalizacji aplikacji.

Stuart Hallows
źródło
1

Spróbuj utworzyć konstruktora usługi, a następnie wywołaj go w ngOnInit () swojego komponentu.

  • Moduł serwisowy

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

  • Składnik

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

Mam nadzieję że to pomoże.

Bhushan Gadekar
źródło
1
@Hongbo chce, aby usługa działała podczas uruchamiania aplikacji, a nie w jednym konkretnym komponencie, który korzysta z usługi
Jarod Moser
Ta naprawdę prosta odpowiedź zadziałała dla mnie. Uwielbiam proste odpowiedzi. Dzięki.
Aggie Jon z 87