Cara menjalankan layanan saat aplikasi dimulai di Angular 2

97

Saya membuat SocketService layanan, pada dasarnya ini menginisialisasi soket untuk membiarkan aplikasi mendengarkan di port. Layanan ini juga berinteraksi dengan beberapa komponen.

// socket.service.ts

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

Saya tahu kode di konstruktor SocketService () hanya mulai berjalan ketika komponen menggunakan SocketService.

Dan biasanya kode di app.ts terlihat seperti ini:

// app.ts

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

Namun, saya ingin layanan ini berjalan saat aplikasi dimulai. Jadi saya membuat trik, tambahkan saja private _socketService: SocketServiceApp's constructor (). Jadi sekarang kodenya terlihat seperti ini:

// app.ts (baru)

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

Sekarang berhasil. Masalahnya terkadang kode dalam konstruktor SocketService () berjalan, terkadang tidak. Jadi bagaimana saya harus melakukannya dengan benar? Terima kasih

Hongbo Miao
sumber
Panduan ini telah membantu saya: angular.io/docs/ts/latest/tutorial/…
Marian07

Jawaban:

130

Jawaban Stuart mengarah ke arah yang benar, tetapi tidak mudah menemukan informasi di APP_INITIALIZER. Versi singkatnya adalah Anda dapat menggunakannya untuk menjalankan kode inisialisasi sebelum kode aplikasi Anda yang lain berjalan. Saya mencari beberapa saat dan menemukan penjelasan di sini dan di sini , yang akan saya rangkum jika mereka menghilang dari web.

APP_INITIALIZER didefinisikan dalam angular / core. Anda memasukkannya ke dalam app.module.ts Anda seperti ini.

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

APP_INITIALIZER adalah OpaqueToken (atau InjectionToken sejak Angular 4) yang mereferensikan layanan ApplicationInitStatus. ApplicationInitStatus adalah penyedia multi . Ini mendukung banyak dependensi dan Anda dapat menggunakannya dalam daftar penyedia Anda beberapa kali. Ini digunakan seperti ini.

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

Deklarasi penyedia ini memberi tahu kelas ApplicationInitStatus untuk menjalankan metode DictionaryService.load (). load () mengembalikan sebuah janji dan ApplicationInitStatus memblokir startup aplikasi sampai janji tersebut diselesaikan. Fungsi load () didefinisikan seperti ini.

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

Atur seperti itu kamus akan dimuat terlebih dahulu dan bagian lain dari aplikasi dapat dengan aman bergantung padanya.

Edit: Ketahuilah bahwa ini akan meningkatkan waktu muat di muka untuk aplikasi Anda berapa lama pun metode load () berlangsung. Jika Anda ingin menghindarinya, Anda dapat menggunakan resolver di rute Anda.

GMK
sumber
Terima kasih untuk ini ... sangat membantu
Gaurav Joshi
5
Ini harus menjadi jawaban yang diterima. Yang saat ini hanya memindahkan satu baris kode dari konstruktor ke initmetode. Sementara konstruktor memang harus dibuat sesederhana mungkin, pemikiran itu saja tidak menjadikannya solusi yang tepat. Menggunakan APP_INITIALIZERtidak.
JP ten Berge
Saya tidak berpikir jawaban yang dipilih salah, karena ini menyelesaikan masalah OP. TAPI , karena saya memiliki masalah serupa pada beberapa pengembangan perpustakaan, saya telah membuka pertanyaan lain di mana jawaban ini akan cocok dengan sempurna.
Machado
Cara terbaik untuk melakukannya
Renil Babu
58

Pindahkan logika dalam SocketServicekonstruktor Anda ke sebuah metode dan kemudian panggil logika tersebut di konstruktor komponen utama Anda ataungOnInit

SocketService

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

Aplikasi

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {
        _socketService.init();
    }
}
bootstrap(App, [SocketService]);
SnareChops
sumber
1
saya tidak mengerti apa logika di balik melakukan hal-hal dalam metode daripada konstruktor dapat Anda jelaskan ini, apa keuntungan melakukan logika dalam metode ini?
Pardeep Jain
1
Pendekatan yang lebih bersih imho
inoabrian
12
Konstruktor harus sesederhana mungkin (biasanya hanya titik injeksi), jika Anda perlu menambahkan logika tambahan, gunakan hook ngOnInit.
Sergio
1
Namun hal lain yang tidak terpikirkan oleh tim .. Semakin saya mengerjakan Angular 4, saya menyadari betapa briliannya kerangka Aurelia yang dibangun. Ia memiliki semua kemungkinan ini langsung dari kotak hanya dengan menambahkan dekorator. Orang-orang itu tahu apa yang mereka lakukan.
Joel Hernandez
1
@CodyBugstein Itu tergantung pada kasus penggunaan Anda. Jika itu hanya api-dan-lupakan maka panggil saja metode async. Jika Anda perlu menunggu hasilnya, Anda dapat mengembalikan a Promisedari init()metode Anda dan kemudian rantai sesuai kebutuhan. Apapun kasusnya, hal itu dapat dilakukan, tetapi mungkin akan sulit dan terserah Anda untuk mengerjakan detailnya. Jika Anda membutuhkan bantuan lebih lanjut, Anda selalu dapat memposting pertanyaan dengan detail masalah Anda dan komunitas akan dengan senang hati membantu Anda.
SnareChops
8

Lihat juga APP_INITIALIZER , yang dideskripsikan sebagai;

Fungsi yang akan dijalankan saat aplikasi diinisialisasi.

Stuart Hallows
sumber
1

Coba Buat konstruktor layanan & kemudian panggil dalam ngOnInit () komponen Anda.

  • Modul Layanan

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

  • Komponen

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

Semoga ini membantu.

Bhushan Gadekar
sumber
1
@Hongbo ingin layanan berjalan saat aplikasi dimulai, bukan di satu komponen tertentu yang menggunakan layanan
Jarod Moser
Jawaban yang sangat sederhana ini berhasil untuk saya. Saya suka jawaban sederhana. Terima kasih.
Aggie Jon dari 87