Как запустить службу при запуске приложения в 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]);
SnareChops
источник
1
Я не понимаю, какая логика стоит в методе, а не в конструкторе, не могли бы вы объяснить это, в чем преимущество выполнения логики в методе?
Pardeep Jain
1
Более чистый подход imho
inoabrian
12
Конструкторы должны быть максимально простыми (обычно только точки внедрения), в случае, если вам нужно добавить дополнительную логику, используйте хук ngOnInit.
Серхио
1
Еще одна вещь, о которой команда не подумала ... Чем больше я работаю над Angular 4, я понимаю, насколько блестяще построен фреймворк Aurelia. У него есть все эти возможности прямо из коробки, просто добавив декоратор. Эти парни знают, что делают.
Joel Hernandez
1
@CodyBugstein Это зависит от вашего варианта использования. Если это просто выстрелил и забыл, просто вызовите метод async. Если вам нужно дождаться результата, вы можете вернуть Promiseиз своего init()метода, а затем связать по мере необходимости. В любом случае это можно сделать, но, вероятно, это будет сложно, и вам придется проработать детали. Если вам нужна дополнительная помощь, вы всегда можете задать вопрос с подробным описанием вашей проблемы, и сообщество с радостью вам поможет.
SnareChops
8

Также см. APP_INITIALIZER , который описывается как;

Функция, которая будет выполняться при инициализации приложения.

Стюарт Хэллоус
источник
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,