Angular - есть ли способ отложить создание экземпляра службы до асинхронной инициализации приложения? - PullRequest
3 голосов
/ 07 июня 2019

У меня есть приложение Angular 5 с перехватчиком HTTP, который вызывает другую службу всякий раз, когда она перехватывает запрос.
Я хочу сделать службу настраиваемой с помощью файла конфигурации, поэтому я попытался использовать службу, которая загружает конфигурацию асинхронно во времяинициализация приложения (с использованием ловушки 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);
  }
}

injected-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
  }
]
...

Результат

console output

1 Ответ

2 голосов
/ 07 июня 2019

InitializerService вызывает HttpClient, который вызывает InterceptorService, что, в свою очередь, вызывает 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));
  }
}
...