Angular InjectionToken APP_INITIALIZER 的实现方法介绍

Jerry Wang 发表于 2022/12/09 09:48:41 2022/12/09
【摘要】 APP_INITIALIZER 是 InjectionToken的一个实例。它是 Angular 提供的内建注入令牌。 Angular会在应用加载时执行这个令牌提供的函数。如果函数返回promise,那么angular会一直等待,直到promise被解析。这将使它成为在应用程序初始化之前执行一些初始化逻辑的理想位置。

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<string>('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<void>((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<any> => { 
    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.

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。