【发布时间】:2022-01-28 16:22:15
【问题描述】:
我想在 App 启动之前加载一个 json 配置文件,以便我可以根据配置选项提供一些服务或其他服务。我使用 APP_INITIALIZER 令牌加载它并且一切正常,直到我需要根据相同的配置选项进行条件路由。我试图通过模块中的 APP_INITIALIZER 加载配置文件,并将此模块导入 AppRoutingModule 和主 AppModule 确保提供相同的实例以不加载配置文件两次。
@NgModule({
declarations: [],
imports: [
CommonModule
],
providers: [
ConfigService,
{
provide: APP_INITIALIZER,
useFactory: (cs: ConfigService, http: HttpClient) => cs.loadConfig(http),
deps: [ConfigService, HttpClient],
multi: true
},
]
})
export class CoreModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
ConfigService
]
};
}
}
这里是配置服务:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable()
export class ConfigService {
proccesId: number;
constructor() {}
loadConfig(http: HttpClient) {
return () => {
return (http.get('/assets/app-config.json') as Observable<any>)
.toPromise()
.then((config) => {
this.processId = config.processId
});
};
}
}
这是我在 AppModule 中导入 CoreModule 的方法(在 AppRoutingModule 中以相同的方式导入):
export function OptionServiceFactory (cs: ConfigService, injector: Injector): OptionService {
if(cs.processId === 1) {
return injector.get(OneOptionService);
} else {
return injector.get(OtherOptionService);
}
}
@NgModule({
imports: [
CoreModule.forRoot(),
],
providers: [
OneOptionService,
OtherOptionService,
{
provide: OptionService,
useFactory: OptionServiceFactory,
deps: [ConfigService, Injector]
}],
bootstrap: [AppComponent]
})
export class AppModule { }
这适用于主 AppModule,应用程序等待 ConfigService 加载 JSON 配置文件,因此我可以在工厂中使用 JSON 填充的 ConfigService。但是 AppRoutingModule 不会等待,因此任何访问 ConfigService 属性的操作都会失败。这是 AppRoutingModule:
const routes: Routes = [];
function routesFactory(cs: ConfigService): Routes {
let rutas: Routes = [
{ path: '', redirectTo: '/same-path', pathMatch: 'full' }
];
/* This fails because processId is undefined because JSON file has not been loaded jet */
if(cs.processId === 1) {
rutas.push({ path: 'same-path', component: OneComponent });
} else {
rutas.push({ path: 'same-path', component: OtherComponent });
}
return rutas;
}
@NgModule({
imports: [
CoreModule.forRoot(),
RouterModule.forRoot(routes)
],
exports: [RouterModule],
providers: [
{ provide: ROUTES, multi: true, useFactory: routesFactory, deps: [ConfigService] }
]
})
export class AppRoutingModule { }
作为一种解决方法,我进行了同步 http 调用以在 AppRoutingModule 中加载 json 文件。现在 AppRoutingModule 中的 routesFactory 是:
function routesFactory(cs: ConfigService): Routes {
let rutas: Routes = [
{ path: '', redirectTo: '/same-path', pathMatch: 'full' }
];
/* Syncronous http request */
var request = new XMLHttpRequest();
request.open('GET', '/assets/app-config.json', false);
request.send(null);
if (request.status === 200) {
let config = JSON.parse(request.responseText);
cs.processId = config.processId;
}
/* Now it doesn't fail because we loaded json syncronously */
if(cs.processId === 1) {
rutas.push({ path: 'same-path', component: OneComponent });
} else {
rutas.push({ path: 'same-path', component: OtherComponent });
}
return rutas;
}
它有效,但不鼓励这样做,现在我在浏览器控制台中收到警告。
[弃用] 主线程上的同步 XMLHttpRequest 是 不推荐使用,因为它对最终用户的有害影响 经验。如需更多帮助,请查看https://xhr.spec.whatwg.org/。
有没有办法在 AppRoutingModule 加载之前加载 JSON 文件?
提前致谢
【问题讨论】:
标签: angular typescript dependency-injection xmlhttprequest