Angular - 有没有办法将服务实例化推迟到异步初始化应用程序?

标签 angular angular-httpclient-interceptors

我有一个带有 HTTP 拦截器的 Angular 5 应用程序,它在拦截请求时调用另一个服务。
我想使用配置文件使服务可配置,所以我尝试使用在应用程序初始化期间异步加载配置的服务(使用 APP_INITIALIZER Hook )。
问题是,在配置服务完成从配置文件加载配置之前,我要使用的服务正在实例化。

有没有办法将服务实例化推迟到配置服务完成加载配置之后?


代码

您可以在 stackblitz 中查看完整示例.
最相关的部分如下:

拦截器.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);
  }
}

注入(inject)依赖.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;
  }
}

初始化器.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));
  }
}

应用程序模块.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
  }
]
...

结果

console output

最佳答案

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));
  }
}

关于Angular - 有没有办法将服务实例化推迟到异步初始化应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56493608/

相关文章:

angularjs - Ionic3 中的自定义字体

由于 Jasmine 中 html 中的自定义元素导致的 Angular 2 组件测试错误

typescript - 为什么我得到 this.http.get(...).subscribe 不是 angular2 中的函数

angular - 可以在 HttpInterceptor 中获取上传进度事件,但不能从 HttpClient 调用中获取吗?

angular - 拦截器没有拦截,尽管只有一个 HttpClientModule

javascript - 为什么路由器会破坏 Angular2 中的生命周期钩子(Hook)?

css - 背景不占用整个页面 Angular CSS