Angular - 有没有办法将服务实例化推迟到应用程序异步初始化?
Angular - Is there a way to defer service instantiation until app is asynchronously initialized?
我有一个带有 HTTP 拦截器的 Angular 5 应用程序,它在拦截请求时调用另一个服务。
我想使用配置文件使服务可配置,所以我尝试使用在应用程序初始化期间异步加载配置的服务(使用 APP_INITIALIZER 挂钩)。
问题是,在配置服务完成从配置文件加载配置之前,我要使用的服务正在实例化。
有没有办法将服务实例化推迟到配置服务完成加载配置之后?
代码
您可以在 stackblitz 中查看完整示例。
最相关的部分如下:
interceptor.service.ts
export class InterceptorService implements HttpInterceptor {
constructor(private dependency: InjectedDependencyService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// use InjectedDependencyService to do something on every intercepted request
const userId = this.dependency.getUserId();
console.log("user id:", userId);
return next.handle(request);
}
}
注入-dependency.service.ts
export class InjectedDependencyService {
userId;
constructor(private initializer: InitializerService) {
this.userId = initializer.config.id;
}
// Do something that relies on the configuration being initialized
getUserId() {
console.log("Is configuration initialized?", !!this.initializer.config.id)
return this.userId;
}
}
initializer.service.ts
@Injectable()
export class InitializerService {
config = {};
constructor(private http: HttpClient) { }
initialize() {
// TODO replace with link to a config file
const url = "https://jsonplaceholder.typicode.com/users/1";
return this.http.get(url).toPromise().then(response => {
this.config = response;
console.log("App initialized", this.config);
}, e => console.error(e));
}
}
app.module.ts
...
export function initializerServiceFactory(initializerService: InitializerService) {
return () => initializerService.initialize();
}
...
providers: [
InitializerService,
InjectedDependencyService,
{
provide: APP_INITIALIZER,
useFactory: initializerServiceFactory,
deps: [InitializerService],
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorService,
multi: true
}
]
...
结果
InitializerService
调用触发 InterceptorService
的 HttpClient,后者又调用 getUserId()
。您希望在使用任何拦截器之前完成初始化。
您可以使用HttpBackend
来绕过所有拦截器。
@Injectable()
export class InitializerService {
config = {};
constructor(private backend: HttpBackend) { }
initialize() {
const http = new HttpClient(this.backend);
const url = "https://jsonplaceholder.typicode.com/users/1";
return http.get(url).toPromise().then(response => {
this.config = response;
console.log("App initialized", this.config);
}, e => console.error(e));
}
}
我有一个带有 HTTP 拦截器的 Angular 5 应用程序,它在拦截请求时调用另一个服务。
我想使用配置文件使服务可配置,所以我尝试使用在应用程序初始化期间异步加载配置的服务(使用 APP_INITIALIZER 挂钩)。
问题是,在配置服务完成从配置文件加载配置之前,我要使用的服务正在实例化。
有没有办法将服务实例化推迟到配置服务完成加载配置之后?
代码
您可以在 stackblitz 中查看完整示例。
最相关的部分如下:
interceptor.service.ts
export class InterceptorService implements HttpInterceptor {
constructor(private dependency: InjectedDependencyService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// use InjectedDependencyService to do something on every intercepted request
const userId = this.dependency.getUserId();
console.log("user id:", userId);
return next.handle(request);
}
}
注入-dependency.service.ts
export class InjectedDependencyService {
userId;
constructor(private initializer: InitializerService) {
this.userId = initializer.config.id;
}
// Do something that relies on the configuration being initialized
getUserId() {
console.log("Is configuration initialized?", !!this.initializer.config.id)
return this.userId;
}
}
initializer.service.ts
@Injectable()
export class InitializerService {
config = {};
constructor(private http: HttpClient) { }
initialize() {
// TODO replace with link to a config file
const url = "https://jsonplaceholder.typicode.com/users/1";
return this.http.get(url).toPromise().then(response => {
this.config = response;
console.log("App initialized", this.config);
}, e => console.error(e));
}
}
app.module.ts
...
export function initializerServiceFactory(initializerService: InitializerService) {
return () => initializerService.initialize();
}
...
providers: [
InitializerService,
InjectedDependencyService,
{
provide: APP_INITIALIZER,
useFactory: initializerServiceFactory,
deps: [InitializerService],
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorService,
multi: true
}
]
...
结果
InitializerService
调用触发 InterceptorService
的 HttpClient,后者又调用 getUserId()
。您希望在使用任何拦截器之前完成初始化。
您可以使用HttpBackend
来绕过所有拦截器。
@Injectable()
export class InitializerService {
config = {};
constructor(private backend: HttpBackend) { }
initialize() {
const http = new HttpClient(this.backend);
const url = "https://jsonplaceholder.typicode.com/users/1";
return http.get(url).toPromise().then(response => {
this.config = response;
console.log("App initialized", this.config);
}, e => console.error(e));
}
}