Как запустить службу при запуске приложения в Angular 2


97

Я создал службу SocketService, в основном она инициализирует сокет, чтобы приложение могло прослушивать порт. Этот сервис также взаимодействует с некоторыми компонентами.

// socket.service.ts

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

Я знаю, что код в SocketService constructor () запускается только тогда, когда компонент использует 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 constructor () выполняются, а иногда нет. Так как мне это сделать правильно? Благодарность


Это руководство мне помогло: 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 (). Если вы хотите избежать этого, вы можете вместо этого использовать преобразователь на своем маршруте.


Спасибо за это ... очень полезно
Гаурав Джоши

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

1
Более чистый подход imho
inoabrian

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

1
Еще одна вещь, о которой команда не подумала ... Чем больше я работаю над Angular 4, я понимаю, насколько блестяще построен фреймворк Aurelia. У него есть все эти возможности прямо из коробки, просто добавив декоратор. Эти парни знают, что делают.
Joel Hernandez

1
@CodyBugstein Это зависит от вашего варианта использования. Если это просто выстрелил и забыл, просто вызовите метод async. Если вам нужно дождаться результата, вы можете вернуть Promiseиз своего init()метода, а затем связать по мере необходимости. В любом случае это можно сделать, но, вероятно, это будет сложно, и вам придется проработать детали. Если вам нужна дополнительная помощь, вы всегда можете задать вопрос с подробным описанием вашей проблемы, и сообщество с радостью вам поможет.
SnareChops


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 хочет, чтобы служба запускалась при запуске приложения, а не в одном конкретном компоненте, который использует службу,
Джарод Мозер,

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