Angular 7 / Rxjs:链接和嵌套可观察对象

Angular 7 / Rxjs: chaining and nesting observables

我有一个交易数据集,我想用给定日期的汇率等额外数据来充实它,然后 post 直接返回我的 api。 但我只得到我的原始交易,没有任何修改,而且我对 Angular 和 Rxjs 还是个新手。所以我需要一些操作员的帮助。

我有一个按钮可以从一个函数中调用多个 api:

// component.ts
public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => this.depositApi.enrichAndSaveDeposit(x));
        }
      );
  }

从本地 api 获取所有有日期的原始交易。 (这个有效)

// depositApiService
public getAllDeposits(): Observable<DepositModel[]> {
    return this.http.get<DepositModel[]>(AppConfig.localJsonServerUrl + AppConfig.api.deposits)
      .pipe(
        catchError(this.handleError('getAllDeposits', null))
      );
  }

我在这里调用外部 api 来获取给定日期的汇率,然后进行一些计算,然后 post 返回本地 api。

但它永远不会进入 mergeMap 部分。

// depositApiService
public enrichAndSaveDeposit(deposit: DepositModel): Observable<DepositModel> {
    return this.apiService.getHistoricEurRate(deposit.date)
      .pipe(
        mergeMap(data => {
          deposit.historicExchangeRate = data.rates.USD;
          deposit.exchangeRate = deposit.sellAmount / deposit.buyAmount;
          deposit.sellAmountInUsd = deposit.sellAmount * data.rates.USD;
          deposit.exchangeRateInUsd = deposit.exchangeRate * data.rates.USD;
          return this.saveLocalDeposit(deposit);
        }), catchError(this.handleError('enrichAndSaveLocalDeposit', deposit))
      );
  }

此处调用外部 api(有效)。

// apiService
public getRemoteExchangeRates(): Observable<ExchangeRateModel> {
    return this.http.get<ExchangeRateModel>(AppConfig.exchangeRateApi + '/latest')
      .pipe(
        catchError(this.handleError('getRemoteExchangeRates', null))
      );
  }

这是post到本地api。 (永远不会达到这一点)

// depositApiService
private saveLocalDeposit(deposit: DepositModel): Observable<DepositModel> {
    return this.http.post<DepositModel>
      (
        AppConfig.localJsonServerUrl + AppConfig.api.deposits,
        deposit,
        { headers: new HttpHeaders().set('Accept', 'application/json') }
      )
      .pipe(
        catchError(this.handleError('saveLocalDeposit', deposit))
      );
  }

问题是您从未订阅从 enrichAndSaveDeposit 编辑的 Observable return,因此永远不会生成 http POST。

订阅然后提供一个 Observer 函数,即使是一个空函数也足够了。

public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => this.depositApi.enrichAndSaveDeposit(x).subscribe(() => {}));
        }
      );
  }

Angular's HttpClient's methods (get, post, ...etc) return 冷 Observables,这意味着它们只在订阅时启动 运行。这很重要,原因有两个:

  • 除非您从该 HttpClient 方法订阅 Observable return,否则不会发出 HTTP 请求。
  • HttpClient 方法的每个订阅都会发出一个请求。

阅读以下内容将有助于您理解冷热 Observable 的区别:

https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339

这是我对类似问题的回答,其中概述了如何解决此问题

此外,我想向您提供一个关于 RxJS 的提示,我认为这是当前问题的一部分。让我们看看您的代码,如下所示。

public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => this.depositApi.enrichAndSaveDeposit(x));
        }
      );
  }

此代码订阅 Observable getAllDeposits,然后说当 returns 有一个值时,使用 enrichAndSaveDeposit 映射该值。但是,您的 enrichAndSaveDeposit 代码也是一个 Observable,因此正如上面所写,永远不会调用它,因为它永远不会被订阅。下面我写了一些可以解决这个特定案例的东西。

public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => {
            this.depositApi.enrichAndSaveDeposit(x)
              .subscribe( // this is the subscribe that is needed to make the second part of the chain work
                enrichedResult => {
                  // do something with the enrichedResult here
                }
              );
          };
        }
      );
  }

希望对您有所帮助。