簡體   English   中英

Angular 服務構造函數在 APP_INITIALIZER 完成之前被觸發

[英]Angular service constructor is being triggered before APP_INITIALIZER can finish

我的應用程序中的根提供的服務和 APP_INITIALIZER 之間似乎存在競爭條件,我不知道如何解決它。

我想確保 APP_INITIALIZER 首先完成,因為被觸發的服務依賴於 APP_INITIALIZER 應該設置的 AppConfig。 由於構造函數首先觸發它使用未定義的值並引發錯誤。

我已經簡化了AppInitService的實現,但是主體是一樣的。 我希望init返回的 promise 在調用 UserSerialService 構造函數之前解析。 目前構造函數首先被調用並導致錯誤,這意味着init promise 永遠不會完成。

正在構建的服務

@Injectable({
  providedIn: 'root'
})
export class UserSerialService {

  public userSerial$: BehaviorSubject<string>;
  private _urlPrefix = '/cldflt/user/api/user/my-serial';

  constructor(private _configService: AppConfigService,
              private _http: HttpClient) {
    this.getUserSerial$().pipe(take(1)).subscribe(res => {
      this.userSerial$ = new BehaviorSubject<string>(res.body.serial)
    })
  }

  public getUserSerial$ = (): Observable<HttpResponse<Serial>> => {
    const url = this._configService.getConfig().baseUrl + `${this._urlPrefix}`;
    return this._http.get<any>(url, { observe: 'response' });
  }
}

模塊

export function initApp(appInitService: AppInitService) {
  console.log("InitApp called");
  return () => appInitService.init();

}

@NgModule({
  declarations: [
  ],
  imports: [
  ],
  entryComponents: [
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initApp,
      deps: [AppInitService],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

應用初始化服務

@Injectable({
  providedIn: 'root'
})
export class AppInitService {

  constructor(private _configService: AppConfigService,
              private _splitService: SplitIOService) { }

  init(): Promise<void>{
    console.log("InitApp called");
    return Promise.resolve().then(() => {
      console.log("Promise complete");
    });
  }
}

我建議你重構你的代碼以正確的方式處理異步,在這種情況下你不會關心執行順序;

class AppConfigService {
  config$ = new ReplaySubject<Configuration>(1);
  setConfig(config: Configuration) {this.config$.next(config)}
  getConfig(): Observable<Configuration> {return this.config$}
}
class UserSerialService {
  // ...
  public getUserSerial$ = (): Observable<HttpResponse<Serial>> => {
    return this._configService.getConfig().pipe(switchMap(({baseUrl}) => 
          this._http.get<any>(url, { observe: 'response' })
    );

  }
}

您可以在初始化完成后使用 Subject 發出信號並訂閱其他服務並通過 mergeMap 等將兩個可觀察對象鏈接在一起嗎?

您可以稍后注入您的_splitService ,因此稍后將構建它以及它的依賴UserSerialService

export class AppInitService {

  constructor(private _configService: AppConfigService,
              private injector: Injector) { }

  init(): Promise<void>{
    console.log("InitApp called");
    return Promise.resolve().then(() => {
      console.log("Promise complete");
    });
  }

  doSomething() {
     const splitService = this.injector.get(SplitIOService);
     splitService.youAreNoLongerAProblem();
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM