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
}
);
};
}
);
}
希望对您有所帮助。
我有一个交易数据集,我想用给定日期的汇率等额外数据来充实它,然后 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
}
);
};
}
);
}
希望对您有所帮助。