Як запустити службу, коли програма запускається в Angular 2


97

Я створив службу SocketService, в основному вона ініціалізує сокет, щоб програма могла слухати порт. Ця послуга також взаємодіє з деякими компонентами.

// socket.service.ts

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

Я знаю, що код у конструкторі SocketService () починає запускатися лише тоді, коли компонент використовує SocketService.

І зазвичай код в app.ts виглядає так:

// app.ts

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

Однак я хочу, щоб ця послуга запускалася під час запуску програми. Тож я зробив фокус, просто додайте private _socketService: SocketServiceконструктор програми (). Тож тепер коди виглядають так:

// app.ts (новий)

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

Зараз це працює. Проблема полягає в тому, що коди в конструкторі () SocketService виконуються, а іноді ні. То як я повинен це робити правильно? Дякую


Цей посібник мені допоміг: angular.io/docs/ts/latest/tutorial/…
Marian07,

Відповіді:


130

Відповідь Стюарта вказує у правильному напрямку, але знайти інформацію на APP_INITIALIZER непросто. Коротка версія - ви можете використовувати її для запуску коду ініціалізації до запуску будь-якого іншого коду вашої програми. Я деякий час шукав і знаходив тут і тут пояснення , які я підсумуватиму на випадок, якщо вони зникнуть з Мережі.

APP_INITIALIZER визначається в angular / core. Ви включаєте його у свій app.module.ts ось так.

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

APP_INITIALIZER - це OpaqueToken (або InjectionToken, починаючи з Angular 4), який посилається на службу ApplicationInitStatus. ApplicationInitStatus - це мультипровайдер . Він підтримує кілька залежностей, і ви можете використовувати його у списку своїх постачальників кілька разів. Його використовують так.

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

Ця декларація постачальника повідомляє класу ApplicationInitStatus про запуск методу DictionaryService.load (). load () повертає обіцянку, і ApplicationInitStatus блокує запуск програми, доки обіцянка не вирішиться. Функція load () визначається так.

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

Налаштуйте так, що словник завантажується спочатку, а інші частини програми можуть безпечно залежати від цього.

Редагувати: майте на увазі, що це збільшить час попереднього завантаження програми, скільки б часу не зайняв метод load (). Якщо ви хочете уникнути цього, замість цього ви можете використати на своєму маршруті резольвер .


Дякую за це ... дуже корисно
Gaurav Joshi

5
Це має бути прийнятою відповіддю. Поточний переміщує лише один рядок коду від конструктора до initметоду. Хоча конструктори дійсно повинні бути максимально простими, але ця думка сама по собі не робить це належним рішенням. Використовуючи APP_INITIALIZERробить.
JP ten Berge

Я не думаю, що обрана відповідь є неправильною, оскільки вона вирішує проблему OP. АЛЕ , оскільки у мене є подібна проблема з розвитком деяких бібліотек, я відкрив ще одне запитання, де ця відповідь ідеально підійде.
Machado

Найкращий спосіб зробити
Реніл Бабу

58

Перемістіть логіку у вашому SocketServiceконструкторі до методу, а потім викличте це у конструкторі вашого основного компонента абоngOnInit

SocketService

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

Додаток

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

1
я не розумію, за якою логікою стоїть щось у методі замість конструктора, чи можете ви пояснити це, у чому перевага використання логіки в методі?
Pardeep Jain


12
Конструктори повинні бути максимально простими (як правило, лише точки введення), якщо вам потрібно додати додаткову логіку, використовуйте гачок ngOnInit.
Серхіо

1
Ще одна річ, про яку команда не замислювалася .. Чим більше я працюю над Angular 4, я усвідомлюю, наскільки блискуче побудований фреймворк Aurelia. Усі ці можливості можна отримати прямо з коробки, просто додавши декоратор. Ці хлопці знають, що роблять.
Джоель Ернандес,

1
@CodyBugstein Це залежить від вашого випадку використання. Якщо це просто «забудь і забудь», тоді просто викликай метод async. Якщо вам потрібно дочекатися результату, ви можете повернути a Promiseз вашого init()методу, а потім ланцюжок за потреби. У будь-якому випадку це можна зробити, але, мабуть, це буде складно, і ви повинні розробити деталі. Якщо вам потрібна подальша допомога, ви завжди можете опублікувати запитання з деталями своєї точної проблеми, і спільнота буде рада вам допомогти.
SnareCops


1

Спробуйте створити конструктор служби, а потім зателефонуйте йому в ngOnInit () вашого компонента.

  • Сервісний модуль

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

  • Компонент

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

Сподіваюся, це допомагає.


1
@Hongbo хоче, щоб служба запускалася під час запуску програми, а не в одному конкретному компоненті, який використовує послугу
Jarod Moser

Ця справді проста відповідь спрацювала для мене. Я люблю прості відповіді. Дякую.
Еггі Джон від 87
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.