angular - Angular 12 APP_INITIALIZER 未在其他模块之前触发
问题描述
我知道这是一个经常被重复的问题,我已经阅读了几乎所有这些问题,因为我一直试图让 app_initializer 启动几个小时,但无济于事。所以最后的手段是这个
我要做的就是动态加载我的 Spring Boot 应用程序的其余端点,以便我可以部署到多个环境。
我的设置如下:
应用配置服务
.....
loadConfig() : Promise<any> {
const jsonFile = 'assets/config/config.json';
return this.httpClient
.get(jsonFile)
.pipe(tap((result) =>{
AppConfigService.settings = <IAppConfig>result;
console.log(AppConfigService.getConfig());
})).toPromise();
}
应用模块
export function initializeConfigData(appConfigService: AppConfigService) {
return (): Promise<any> => {
console.log("in app init fn");
return appConfigService.loadConfig2();
}
}
...
providers: [AppConfigService,
{
provide: APP_INITIALIZER, useFactory: initializeConfigData, deps: [AppConfigService], multi: true
}]
发生的事情是我的应用程序中有多个模块。例如,auth 模块有一个服务,它对 rest 端点进行身份验证调用,并且似乎在应用初始化程序完成之前就触发了。
所以在我加载应用程序后,我最终得到了
Uncaught TypeError: Cannot read property 'root' of undefined
在控制台上(root 是我的配置 json 数据中的关键)
我已经阅读了多篇文章,并在我的 loadConfig 方法中尝试了很多东西,比如尝试返回一个新的 Promise((resolve, reject) =>.... 但没有任何帮助。因为我在 12 岁,我也尝试了 Observables,但没有任何效果。无论我做什么,我的 AuthenticationService 都失败了,表明它无法读取该属性。
我错过了什么?或者这是当您有多个模块时尝试让 app_initializer 工作时的行为。
只是为了测试一下,我尝试了一个简单的 setTimeout(没有读取配置以获取 URL),并且按预期触发。所以这该死的东西着火了,但我认为这是一个时间问题......我在这里束手无策,所以任何帮助都将不胜感激。
谢谢!
解决方案
我测试了上面的场景(使用提供的代码),似乎一切正常(我没有多个模块,只有 app 模块)。我在里面记录配置AppComponent.ngOnInit
,它总是在那里有配置值。尽管如此,我想提出另一种方法。您AppConfigService
可以使用Observable
. 这样,所有其他依赖于配置的东西都会等到它在那里。
@Injectable({
providedIn: 'root',
})
export class AppConfigService {
private configSource = new ReplaySubject<IAppConfig>(1);
// public static config: IAppConfig | null = null;
public config$: Observable<IAppConfig> = this.configSource.asObservable();
constructor(private http: HttpClient) {}
loadConfig = (): Observable<any> => {
const jsonFile = 'assets/config/config.json';
return this.http.get(jsonFile).pipe(
tap((result) => {
// AppConfigService.config = result;
this.configSource.next(result);
})
);
};
}
AppModule 看起来与您所拥有的几乎相同(除了我没有添加AppConfigService
到 providers 数组中,因为它已经是providedIn: 'root'
):
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeConfigData,
deps: [AppConfigService],
multi: true,
},
],
每当您需要使用您的配置时,只需注入AppConfigService
并执行您的 http 调用:
@Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(
private appConfigService: AppConfigService,
private http: HttpClient
) {}
getUser(): Observable<any> {
return this.appConfigService.config$.pipe(
switchMap((config) => this.http.get(`${config.root.backendUrl}/users`))
// ...
);
}
}
推荐阅读
- php - 如何使用 domPDF 在 Laravel 中打印刀片文件的某些部分
- scala - 将Scala泛型绑定到上层类中没有的函数
- crystal-reports - Crystal Reports 登录失败,网络路径出错,但映射驱动器正常
- php - getId3 以秒为单位获取视频持续时间
- c# - 将通用急切加载方法从 EF6 转换为 EF Core
- android - 如何构建 PackageInstaller 源代码?
- c# - 如何在长循环之前立即更新显示的文本框
- powershell - PowerShell 更新现有计划任务触发器开始日期和时间
- android - requestPermission:如何等到被授予?
- python - pythonic方法来识别列表中的第一个真实条件