Angular中如何在APP_INITIALIZER执行完成后提供自定义InjectionToken
问题核心原因
Angular 启动时会先解析所有普通提供者的依赖,若FORMATS在应用初始化阶段(比如被其他启动期服务、根组件注入),它的工厂函数会在APP_INITIALIZER的异步任务执行完成前触发,此时ConfigService里的配置还未加载完成。
解决方案
方案1:合并赋值逻辑到APP_INITIALIZER流程(改造成本最低)
适合绝大多数场景,不需要调整现有依赖结构:
- 先修改
ConfigService,新增内部缓存属性:
@Injectable({ providedIn: "root" }) export class ConfigService { // 新增缓存配置的内部属性 private formats: Formats | null = null; constructor() {} // 配置加载完成后调用,存储formats setFormats(formats: Formats) { this.formats = formats; } getFormats() { return this.formats; } }
- 修改
loadConfig工厂函数,加载完配置后先给ConfigService赋值再resolve:
export function loadConfig(configService: ConfigService, http: HttpClient): () => Promise<Config> { return async () => { // 保留你原有加载配置的逻辑,比如从接口/本地文件拉取 const config = await http.get<Config>('/assets/config.json').toPromise(); // 加载完成后先把formats存入ConfigService configService.setFormats(config.formats); return config; }; }
- 保留原有
FORMATS的注册逻辑即可。Angular 会等所有APP_INITIALIZER的异步任务全部执行完成后,才会初始化根组件、渲染页面,也才会注入业务层用到的依赖,此时ConfigService里的formats已经赋值完成,assignFormat自然能拿到正确的值。
方案2:FORMATS需在初始化阶段被依赖的场景
如果你的FORMATS会被APP_INITIALIZER链路上的其他服务依赖,可以把FORMATS的返回值改为Promise,消费方按需等待:
- 先给
ConfigService新增加载完成通知能力:
import { Subject } from 'rxjs'; @Injectable({ providedIn: "root" }) export class ConfigService { private formats: Formats | null = null; // 配置加载完成的通知Subject public configLoaded$ = new Subject<void>(); constructor() {} setFormats(formats: Formats) { this.formats = formats; this.configLoaded$.next(); this.configLoaded$.complete(); } getFormats() { return this.formats; } }
- 修改
FORMATS的类型定义和工厂函数:
export const FORMATS = new InjectionToken<Promise<Formats>>("formats") export function assignFormat(configService: ConfigService): Promise<Formats> { return new Promise((resolve) => { configService.configLoaded$.subscribe(() => { resolve(configService.getFormats()); }) }); }
- 消费
FORMATS的地方用async管道或者await等待取值即可。
兜底强制等待方案
可以直接在FORMATS的工厂依赖中注入APP_INITIALIZER,强制等待所有初始化任务完成再执行逻辑:
providers: [{ provide: APP_INITIALIZER, useFactory: loadConfig, deps: [HttpClient, ConfigService], multi: true }, { provide: FORMATS, useFactory: async (configService: ConfigService, initializers: Promise<void>[]) => { // 等待所有APP_INITIALIZER的任务执行完成再返回结果 await Promise.all(initializers); return configService.getFormats(); }, deps: [ConfigService, APP_INITIALIZER] }]
内容的提问来源于stack exchange,提问作者frankfullstack
相关产品推荐
相关产品推荐

