Angular rxjs 混合 observable 和 promises

Angular rxjs mix observable and promises

我正在开发一个 Angular 应用程序,我使用 Rxjs、Observables 和所有东西将数据从我的数据访问层传输到组件。

我有一个服务可以获取 Bootstrapping 数据(名为 B)。 另一个服务(名为 A)获取这些数据并通过 Subject 将它们提供给组件。

我的目标是将这些数据保留在我的服务 A 中,但仅限于我第一次获取数据时。所以,我将使用 Promise。

我需要对主题 "subscribe" 的承诺,然后直接 "unsubscribe"。

我尝试了 BehaviorSubject、ReplaySubject,但 Promise 从未被调用...

Bootstrap 服务

export class BService {
  propsFetched: Subject<BootstrapProperties> = new Subject<BootstrapProperties>();

  constructor(private httpClient: HttpClient) { //... }

  init() {
    this.fetchBootstrapProperties().then(
      (res) => {
        // ...
        this.propsFetched.next({ ...res });
      }
    );
  }

  private fetchBootstrapProperties(): Promise<BootstrapProperties> {
    const url = UrlResolver.resolveUrl(UrlResolver.EndPoint.BOOTSTRAP);
    return this.httpClient.get<BootstrapProperties>(url).toPromise();
  }

  getDefaultData(): Observable<Data> {
    return this.propsFetched.pipe(map(data => {
      // Some data computation
      return data;
    }));
  }
}

获取数据并将其传输到组件的服务

export class AService {
  sub$ = new BehaviorSubject<Data>();

  constructor(private bService: BService) {
    // This one works, it's used by my component.
    this.sub$ = this.bService.getDefaultData() as BehaviorSubject<Data>;

    // Now, I want to "keep a copy" of these data, ... But my promise never fires.
    this.sub$.toPromise().then(d => console.log(d));
}

模块和Bootstrapping 配置

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    // ...
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: init,
      deps: [BService],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

export function init(bService: BService) {
  return () => bService.init();
}

我建议继续使用 Observables。管道运算符 share 将 Observable 的结果共享给订阅此 Observable 的每个人。只调用一次。

export class BService {
  public fetchBootstrapProperties$: Observable<BootstrapProperties>;

  constructor() {
    this.fetchBootstrapProperties$ = this.httpClient.get<BootstrapProperties>(url).pipe(
      map(data => {
        // computation
        // return data
      }),
      share()
    );
  }
}

export class AService {
  constructor(bService: BService) {
    this.bService.fetchBootstrapProperties$.subscribe(data => {
      // get your data
    );
  }
}