背景:我需要在应用程序启动期间执行几次初步检查(1)从./assets/config.json
文件中读取angular app的配置并获取API从此处结束端点,(2)对第一步中获取的端点进行API调用,并从后端加载一些设置。
目标:能够使用APP_INITIALIZER
(例如A和B)初始化两个服务,其中B依赖于A。check out this stackblitz来查看问题>
我尝试过的事情:如果图片中没有第二部分(能够向后端发出API请求),那么我设法使用了角度APP_INITIALIZER
为了完成工作,我随后搜索了一些文章,发现其中一本Managing dependencies among App Initializers in Angular,其中列出了3种方法,第三种是推荐的方法(因为它易于维护),但是我不太了解所有方法其中,我相信作者没有包括每种方法的完整代码实现(我确实知道是作者要求是否提供代码示例,我可能错了)。如果有经验的人可以分享相同的知识,我将不胜感激。
PS:我没有在这里添加任何代码,因为我不确定我尝试过的内容是否合理,但我很乐意添加一些代码。
Stackblitz1(单个APP_INITIALIZER
)-https://stackblitz.com/edit/angular-puaw7a
[问题] Stackblitz2(多个APP_INITIALIZER
)-https://stackblitz.com/edit/angular-7uqijv
答案 0 :(得分:1)
我认为您实际上并不需要初始化程序。您只是拥有其他服务所依赖的价值。代码中的问题是您有一个异步值,并尝试将其公开为同步值。
我认为,只要将配置公开为Observable并在需要的地方“等待”即可解决您的问题。好处是在完成配置请求之前,应用程序将尽可能多地加载。
例如,shareReplay(1)
运算符将把该项保留在内存中,并将HTTP请求推迟到实际需要时:
export class ConfigService {
configData$ = this.httpClient.get<{config1:string}>('./assets/config.json').pipe(shareReplay(1));
constructor(private httpClient: HttpClient) { }
}
现在,您的第二项服务可以等待第一项服务中的configData。或者只是通过可观察的管道对其进行转换,然后将其进一步暴露为可观察的形式,以将所有内容推迟到实际需要为止。
@Injectable({
providedIn: 'root'
})
export class SettingsService {
settingsData$ = this.configService.configData$.pipe(
map(c => c.config1 + '...and config service dependent action'),
shareReplay(1), // also keep the value in memory maybe?
);
constructor(
private httpClient: HttpClient,
private configService: ConfigService
) { }
}
export class HelloComponent implements OnInit {
@Input() name: string;
dataFromConfigSvc: Observable<string>;
constructor(private configService: ConfigService) { }
ngOnInit() {
// you could either use async pipe in the template or subscribe here and get the value
this.dataFromConfigSvc = this.configService.configData$.pipe(map(c => c.config1));
}
}
答案 1 :(得分:1)
只需使用
useFactory: (appConfigSvc: ConfigService,settingsService:SettingsService) => {
return () => {
return appConfigSvc.loadConfig().then(()=>{
return settingsService.loadConfig()
});
};
}
答案 2 :(得分:1)
我知道已经有一段时间了,但我还有另一个解决方案。 我为依赖于配置的初始化函数做了包装。
在应用模块中定义提供者如下:
providers: [
{ provide: APP_INITIALIZER, useFactory: initConfig, deps: [...], multi: true },
{
provide: APP_INITIALIZER,
useFactory: withConfig(initCrm, [initCrm_Deps]), // use wrapper
deps: [Injector], // Injector is required for withConfig
multi: true
}
]
包装函数:
export function withConfig(factory: Function, deps: any[]) {
return (injector: Injector) => {
return () => AppConfig.instance$
.toPromise()
.then(() => {
// Inject dependencies
const depsInstances = deps.map(d => injector.get(d));
// Execute original function
return factory.apply(globalThis, depsInstances)();
});
};
}
AppConfig.instance$
是一个 Subject
,它在加载配置后发出值。