javascript - Angular 2 alt modülünde servis başlatmayı zorlamak (AngularJS run bloğuna bir alternatif)


Uygulama içinde kullanım için hazırlanması amacıyla bazı üçüncü taraf modülleri saran, hizmetini oluşturup başlatan alt modülde bir servisim var.

@Injectable()
class SubmoduleInitializerService {
    constructor (thirdPartyService: ThirdPartyService) {
      thirdPartyService.initialize(...);
      ...
    }
}

@NgModule({
    imports: [ThirdPartyModule],
    exports: [ThirdPartyModule],
    providers: [
        ThirdPartyService,
        SubmoduleInitializerService
    ]
})
class AppSubmodule {}

ThirdPartyService uygulamaya doğrudan enjekte edilmez ancak diğer ThirdPartyModule birimleri tarafından kullanılır, bu yüzden SubmoduleInitializerService ThirdPartyService ile aynı enjektörde veya üst enjektörde enjekte edildiği sürece her şey yolundadır:

export class AppComponent {
    constructor(
      /* DO NOT REMOVE! BAD THINGS HAPPEN! */
      submoduleInitializerService: SubmoduleInitializerService
    ) {}
    ...
}

Kötü bir kalıp olduğu kanıtlandı çünkü SubmoduleInitializerService sınıfta veya şablonda kullanılmıyorsa neden AppComponent'te enjekte edilmiş olarak kalması gerektiği belli değil (zaten bir kez kazara kaldırılmıştı).

Temelde AppSubmodule modülüne Angular 1.x angular.module(...).run(...) bloğuna bir alternatif gerekiyor.

Burada seçenekler neler?

Cevap #1

APP_INITIALIZER (belgelenmemiş) servisi, Angular 2'de (eşzamanlı başlatma özelliği sayılmadan) AngularJS config/run bloklarının görevini oldukça iyi bir şekilde yerine getirir.

Sadece SubmoduleInitializerService öğesini hevesle başlatan noop başlatma bloğu için şudur:

@NgModule({
    imports: [ThirdPartyModule],
    exports: [ThirdPartyModule],
    providers: [
        ThirdPartyService,
        SubmoduleInitializerService,
        {
            provide: APP_INITIALIZER,
            useFactory: () => () => {},
            deps: [SubmoduleInitializerService],
            multi: true
        }
    ]
})
class AppSubmodule {}

APP_INITIALIZER çoklu sağlayıcı olduğundan, modüllerin yüklendiği sırayı takip eden her uygulama için birkaç başlatma işlevine sahip olmaya izin verir.

Senkron başlatma için daha kısa (ve muhtemelen daha uygun) alternatif, servisi modülün yapıcısına enjekte etmektir:

@NgModule({
    imports: [ThirdPartyModule],
    exports: [ThirdPartyModule],
    providers: [
        ThirdPartyService,
        SubmoduleInitializerService
    ]
})
class AppSubmodule {
    constructor(sis: SubmoduleInitializerService) {}
}

Bu cevaptan açıklandığı gibi, APP_INITIALIZER bazı özellikleri bakımından config bloğuyla da benzerlik gösterir, çünkü bileşen başlatılmasından önce servisleri yapılandırmak için kullanılır ve yarış durumu (race condition) oluşumuna açıktır (örneğin, APP_INITIALIZER Router’ı yapılandırmak için kullanıldığından, başka bir APP_INITIALIZER içine enjekte edilmesi döngüsel bağımlılığa yol açar).

İlgili makaleler