Angular中APP_INITIALIZER依赖失效:EnvironmentService未定义
我尝试用 APP_INITIALIZER 在应用初始化阶段调用接口加载环境配置,但执行 runInitializers 时,EnvironmentService 一直是 undefined。这个功能最初在外部类库实现,类库代码如下:
// environmentService is undefined function loadEnvironmentalValues(environmentService: EnvironmentService): () => Observable<EnvironmentValue> { return () => environmentService.getEnv().pipe(tap(() => console.log('ENV LOADED'))); } @NgModule({ declarations: [], imports: [HttpClientModule, NgxPermissionsModule], exports: [], providers: [ EnvironmentService, { provide: APP_INITIALIZER, useFactory: () => loadEnvironmentalValues, deps: [EnvironmentService], multi: true }] }) export class OurLibraryModule{ constructor() { } }
之后我在引用该类库的主应用里也试了相同逻辑,结果 EnvironmentService 还是 undefined:
// again environmentService is undefined function loadEnvironmentalValues(environmentService: EnvironmentService): () => Observable<EnvironmentValue> { console.log('service je ', environmentService, !!environmentService); return () => environmentService.getEnv().pipe(tap(() => console.log('ENV LOADED from app'))); } imports: [ OurLibraryModule ], providers: [ EnvironmentService, { provide: APP_INITIALIZER, useFactory: () => loadEnvironmentalValues, deps: [EnvironmentService], multi: true },
EnvironmentService 的实现代码:
@Injectable({ providedIn: 'root', }) export class EnvironmentService { private readonly environmentValues$: Observable<EnvironmentValue>; constructor(private httpClient: HttpClient) { this.environmentValues$ = this.getEnvironmentValues().pipe(share()); } getEnv(key?: string): Observable<EnvironmentValue> { if (key) { return this.environmentValues$.pipe( map((environmentConfig: EnvironmentValue) => environmentConfig[key]) ) } else { return this.environmentValues$; } } private getEnvironmentValues(): Observable<EnvironmentValue> { return this.httpClient.get<EnvironmentValue>(CONFIG_PATH).pipe( catchError((error: unknown) => { // eslint-disable-next-line no-console console.log('UNABLE TO LOAD ENVIRONMENT VALUES'); // eslint-disable-next-line no-console console.error(error); throw error; })); } }
想问下我遗漏了哪些配置?用 APP_INITIALIZER 前还要做什么前置操作吗?
问题原因及解决方案
1. APP_INITIALIZER 工厂函数写法错误
你的 useFactory 返回的是 loadEnvironmentalValues 函数本身,而不是调用该函数后返回的初始化函数。Angular 注入依赖后,需要工厂函数直接接收注入的服务实例,再生成初始化逻辑函数。正确写法应该是:
修改类库和主应用中的 APP_INITIALIZER 配置:
// 类库中的正确配置 { provide: APP_INITIALIZER, useFactory: (envService: EnvironmentService) => loadEnvironmentalValues(envService), deps: [EnvironmentService], multi: true } // 也可以直接简化写法 useFactory: (envService: EnvironmentService) => () => envService.getEnv().pipe(tap(() => console.log('ENV LOADED'))),
原来的写法中,useFactory: () => loadEnvironmentalValues 只是返回了函数本身,没有把注入的 EnvironmentService 传进去,导致 loadEnvironmentalValues 执行时参数为 undefined。
2. 移除重复的 EnvironmentService 提供
EnvironmentService 已经通过 providedIn: 'root' 声明为根注入服务,不需要在类库和主应用的 providers 数组中再次添加。重复提供可能导致注入实例不一致,甚至出现初始化异常。直接删除两处 providers 中的 EnvironmentService 即可。
3. 确保初始化流正常完成
Angular 的 APP_INITIALIZER 支持返回 Promise 或 Observable,返回 Observable 时 Angular 会自动订阅,但要确保接口能正常访问、流能正常完成。如果 CONFIG_PATH 错误或接口请求失败,会导致初始化中断,需要提前校验接口地址和权限。
修正后的类库模块代码示例
function loadEnvironmentalValues(environmentService: EnvironmentService): () => Observable<EnvironmentValue> { return () => environmentService.getEnv().pipe(tap(() => console.log('ENV LOADED'))); } @NgModule({ declarations: [], imports: [HttpClientModule, NgxPermissionsModule], exports: [], providers: [ { provide: APP_INITIALIZER, useFactory: (envService: EnvironmentService) => loadEnvironmentalValues(envService), deps: [EnvironmentService], multi: true }] }) export class OurLibraryModule{ constructor() { } }
主应用中的修正
移除 providers 中的 EnvironmentService,并修正 APP_INITIALIZER 的工厂函数:
function loadEnvironmentalValues(environmentService: EnvironmentService): () => Observable<EnvironmentValue> { console.log('service je ', environmentService, !!environmentService); return () => environmentService.getEnv().pipe(tap(() => console.log('ENV LOADED from app'))); } imports: [ OurLibraryModule ], providers: [ { provide: APP_INITIALIZER, useFactory: (envService: EnvironmentService) => loadEnvironmentalValues(envService), deps: [EnvironmentService], multi: true },
内容的提问来源于stack exchange,提问作者Jakub Šmiga

