Como executar um serviço quando o aplicativo é iniciado em Angular 2

99

Criei um serviço SocketService, basicamente ele inicializa o soquete para permitir que o aplicativo escute na porta. Este serviço também interage com alguns componentes.

// socket.service.ts

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

Eu sei que o código no construtor de SocketService () só começa a ser executado quando um componente usa SocketService.

E geralmente o código em app.ts se parece com isto:

// app.ts

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

No entanto, quero que esse serviço seja executado quando o aplicativo for iniciado. Então fiz um truque, basta adicionar private _socketService: SocketServiceo construtor do App (). Portanto, agora os códigos são assim:

// app.ts (novo)

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

Agora funciona. O problema às vezes é que os códigos no construtor () de SocketService são executados, às vezes não. Então, como devo fazer isso corretamente? obrigado

Hongbo Miao
fonte
Este guia me ajudou: angular.io/docs/ts/latest/tutorial/…
Marian07

Respostas:

135

A resposta de Stuart aponta na direção certa, mas não é fácil encontrar informações no APP_INITIALIZER. A versão curta é que você pode usá-lo para executar o código de inicialização antes que qualquer outro código do aplicativo seja executado. Procurei um pouco e encontrei explicações aqui e aqui , que vou resumir caso desapareçam da web.

APP_INITIALIZER é definido em angular / núcleo. Você o inclui em seu app.module.ts assim.

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

APP_INITIALIZER é um OpaqueToken (ou um InjectionToken desde Angular 4) que faz referência ao serviço ApplicationInitStatus. ApplicationInitStatus é um provedor múltiplo . Ele oferece suporte a várias dependências e você pode usá-lo em sua lista de provedores várias vezes. É usado assim.

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

Esta declaração do provedor informa a classe ApplicationInitStatus para executar o método DictionaryService.load (). load () retorna uma promessa e ApplicationInitStatus bloqueia a inicialização do aplicativo até que a promessa seja resolvida. A função load () é definida assim.

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

Configurado dessa forma, o dicionário é carregado primeiro e as outras partes do aplicativo podem depender dele com segurança.

Editar: Esteja ciente de que isso aumentará o tempo de carregamento inicial para seu aplicativo, independentemente do tempo que o método load () levar. Se quiser evitar isso, você pode usar um resolvedor em sua rota.

GMK
fonte
Obrigado por isso ... muito útil
Gaurav Joshi
5
Esta deve ser a resposta aceita. O atual move apenas uma linha de código de um construtor para um initmétodo. Embora os construtores devam de fato ser mantidos o mais simples possível, esse pensamento por si só não o torna uma solução adequada. Usando APP_INITIALIZERfaz.
JP ten Berge
Não acho que a resposta selecionada esteja errada, pois resolve o problema de OP. MAS , como tenho um problema semelhante no desenvolvimento de algumas bibliotecas, abri outra pergunta onde essa resposta se encaixaria perfeitamente.
Machado
A melhor maneira de fazer
Renil Babu
58

Mova a lógica em seu SocketServiceconstrutor para um método em vez disso e chame-o no construtor de seu componente principalngOnInit

SocketService

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

Aplicativo

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {
        _socketService.init();
    }
}
bootstrap(App, [SocketService]);
SnareChops
fonte
1
Eu não entendo qual é a lógica por trás de fazer coisas no método em vez do construtor você poderia explicar isso, qual é a vantagem de fazer a lógica no método?
Pardeep Jain
1
Uma abordagem mais limpa imho
inoabrian
12
Os construtores devem ser o mais simples possível (normalmente apenas pontos de injeção), caso você precise adicionar lógica extra, use o gancho ngOnInit.
Sergio
1
Outra coisa que a equipe não pensou. Quanto mais trabalho no Angular 4, percebo o quão brilhante é a estrutura do Aurelia. Ele tem todas essas possibilidades prontas para usar, bastando adicionar um decorador. Esses caras sabem o que estão fazendo.
Joel Hernandez
1
@CodyBugstein Depende do seu caso de uso. Se for apenas disparar e esquecer, basta chamar o método assíncrono. Se você precisar esperar pelo resultado, pode retornar a Promisedo seu init()método e então encadear conforme necessário. Seja qual for o caso, isso pode ser feito, mas provavelmente será difícil e caberá a você resolver os detalhes. Se precisar de mais ajuda, você pode postar uma pergunta com detalhes de seu problema exato e a comunidade ficará feliz em ajudá-lo.
SnareChops
8

Consulte também APP_INITIALIZER , que é descrito como;

Uma função que será executada quando um aplicativo for inicializado.

Stuart Hallows
fonte
1

Tente criar o construtor de serviço e chame-o em ngOnInit () do seu componente.

  • Módulo de Serviço

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

  • Componente

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

Espero que isto ajude.

Bhushan Gadekar
fonte
1
@Hongbo deseja que o serviço seja executado quando o aplicativo for iniciado, não em um componente específico que está usando o serviço
Jarod Moser
Esta resposta realmente simples funcionou para mim. Adoro respostas simples. Obrigado.
Aggie Jon de 87 de