angular 仅在填充了 indexedDb table 时才在组件中加载数据

angular load data in component only when indexedDb table is populated

在我的服务中,我有这个:

  synchronizeCitiesOnLogin() {
    ....
    this.getCitiesFromApi().subscribe(
      cities => {
        cities.map((city) => {
            this.addCityToIndexedDb(city);
        });
      }
    );
  }
  getCitiesFromApi() {
    ....
    return this.apiClient.get(url, { })
      .pipe(
        map((response: any) => response.data ),
        catchError(errorRes => {
          return throwError(errorRes);
        })
      );
  }
  addCitiesToIndexedDb(city) {
    this.cityTable
      .add(city)
      .then(async () => {
        const allItems: CityModel[] = await this.cityTable.toArray();
      })
      .catch(e => {
        alert('Error: ' + (e.stack || e));
      });
  }
    getData(): Promise<any> {
        return this.getDataFromIndexedDb()
    }
    private async getDataFromIndexedDb() {
       ...
       ... 
       return mydata
    }

在我的组件中:

ngOnInit() {
    this.myService.getData().then(data => {
      this.worldCities= data;
    });
}

因为我有很多从 API 收到的数据,所以需要一些时间才能将它们全部保存在 IndexedDB 中。当我加载页面时,“水果”对象将为空,因为数据尚未保存在 IndexedDB 中...... 如果我在 2-3 秒内添加一个 settimeout,它就可以工作,但肯定它应该是解决它的更好方法 有人可以帮我吗? 谢谢

可以考虑在myService中加一个BehaviorSubject

private synchronized$ = new BehaviorSubject(false);

此后你需要以某种方式捕捉城市插入 indexeddb 的完成,看起来可能像

import { from } from 'rxjs';

synchronizeCitiesOnLogin() {
  this.getCitiesFromApi().pipe(
    switchMap((cities) => combineLatest(
      cities.map(city => from(this.cityTable.add(city)))
    )),
    tap(() => {
      this.synchronized$.next(true);
    })
  ).subscribe()
}

然后您可以确保在访问数据之前同步数据:

 getData(): Promise<any> {
    return this.synchronized$.pipe(
      filter(synchronized => synchronized),
      first(),
      switchMap(() => from(this.getDataFromIndexedDb()))
    ).toPromise();
 }

当然可以使上面的内容更具可读性,因为我强烈建议使用 ngx-indexed-db 来完整 RxJs,以避免在 observables 和 promise api 之间不断切换。