APP_INITIALIZER 是 InjectionToken的一个实例。它是 Angular 提供的内建注入令牌。
Angular会在应用加载时执行这个令牌提供的函数。如果函数返回promise,那么angular会一直等待,直到promise被解析。这将使它成为在应用程序初始化之前执行一些初始化逻辑的理想位置。
Angular 注入器使用 DI 令牌来定位 Angular providers 中的依赖项。我们使用令牌在提供者中注册依赖项:
providers :[{ provide: token, useClass: SomeService }]
上面代码里的 token
,可以是一个 type,一个字符串,或者是 InjectionToken 的一个实例。
- type 的例子:
providers :[{ provide: productService, useClass: productService}]
- 字符串的例子:
providers :[ {provide:'MESSAGE', useValue: 'Hello Angular'}]
当所使用的类型没有运行时表示
时,例如注入接口、可调用类型(callable type) 等,就会使用 InjectionToken - TypeScript 代码里的 interface,被编译成 JavaScript 之后,后者从编程语言层面不存在 interface 这种 representation. 此时可以使用 InjectionToken.
export const HELLO_MESSAGE = new InjectionToken('Hello Angular');
providers :[ { provide: HELLO_MESSAGE, useValue: 'Hello World!' }];
如前所述,APP_INITIALIZER在应用程序初始化时运行。Angular会暂停应用的初始化,直到APP_INITIALIZER提供的所有函数运行完毕。如果其中任何一个初始化器返回一个promise,那么angular就会等待它的解析,然后再继续进行App的初始化。
这使我们有机会连接到初始化进程并运行一些应用程序自定义逻辑。可以加载运行时配置信息。从后台加载重要数据等。
看一个例子。新建文件 app-init.service.ts
:
import { Injectable } from '@angular/core';
@Injectable()
export class AppInitService {
constructor() {
}
Init() {
return new Promise((resolve, reject) => {
console.log("AppInitService.init() called");
////do your initialisation stuff here
setTimeout(() => {
console.log('AppInitService Finished');
resolve();
}, 6000);
});
}
}
app.module.ts 的实现:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AboutUsComponent } from './about-us.component';
import { HomeComponent } from './home.component';
import { ContactUsComponent } from './contact-us.component';
import { AppInitService } from './app-init.service';
export function initializeApp1(appInitService: AppInitService) {
return (): Promise => {
return appInitService.Init();
}
}
@NgModule({
declarations: [
AppComponent, AboutUsComponent,HomeComponent,ContactUsComponent
],
imports: [
HttpClientModule,
BrowserModule,
AppRoutingModule,
],
providers: [
AppInitService,
{ provide: APP_INITIALIZER,useFactory: initializeApp1, deps: [AppInitService], multi: true}
],
bootstrap: [AppComponent]
})
export class AppModule { }
上面的代码,使用了 InjectionToken APP_INITIALIZER
来提供函数 initializeApp1,后者调用了我们 service class 的 init 方法。
Angular的依赖注入会把依赖注入到类和组件中,但不会注入到函数中。而我们的initializeApp1是一个函数,需要将AppInitService作为参数注入。因此我们通过使用 deps
标志来做到这一点,并让 Angular 知道它需要创建一个AppInitService的实例,并将它注入到initializeApp1函数中。
multi: true
创建 multi provider DI 令牌。这意味着可以为DI令牌提供提供程序数组。
如果 multi: false(默认值)
被设置并且多次使用一个令牌,最后注册的将令牌将覆盖之前所有的令牌。也就是说,令牌只能有一个 provider.