Angular HttpClient的可观察对象会反复触发



设置如下。有人用包含id的url来调用我的angular应用,以显示带有该id的对象的属性。就像网上商店一样。

http://myFrontend/productDetails/10

然后使用ActivatedRoute获取id (10)并将其传递到HttpClient以从后端获取所请求的数据。

this.route.params.pipe(map(params => params.id)).subscribe(id => {
const params = new HttpParams().set('id', id);
this.httpClient.get<Product>('http://myBackend/product/', {params})
.subscribe(product => this.product = product);
});

当用户从这条路线导航到不同产品的相同路线时,问题就会显现出来。假设你在http://myFrontend/productDetails/10。有一个Observable等待后端返回id为10的产品,并将其存储到一个组件变量中。然后单击next以导航到http://myFrontend/productDetails/11。创建一个新的Observable,等待id为11的产品将其存储到相同的组件变量中。

我真的不明白为什么,但是当我想获取产品11时,返回产品10的第一个Observable再次触发。包括对http://myBackend/product/?id=10的重复http请求。这反过来又会导致竞争条件,因为两个Subscriptions都将其结果写入相同的组件变量。

我可以通过在可观察对象第一次返回后立即取消订阅或通过take(1)管道来阻止这种情况的发生,但我想了解为什么会发生这种情况。

this.route.params在每次参数改变时触发。这意味着每次参数改变时,它都会创建一个新的订阅。正如您在示例中所看到的,嵌套订阅通常是一种反模式。如果你想链接可观察对象,你可以使用所谓的高阶映射操作符,例如concatMap、mergeMap、switchMap或排气图。您可以做的另一件事是不通过调用subscribe显式订阅,而是可以直接在模板中利用async管道。这将自动取消订阅,这可以防止内存泄漏(这在您的情况下不是问题)。试试这个:

this.route.params.pipe(concatMap(params => {
const p = new HttpParams().set('id', params.id);
return this.httpClient.get<Product>('http://myBackend/product/', {p})       
}).subscribe(product => this.product = product);

let product$ = this.route.params.pipe(concatMap(params => {
const p = new HttpParams().set('id', params.id);
return this.httpClient.get<Product>('http://myBackend/product/', {p})       
})
...in the template
<div *ngIf="product$ | async as product">....</div>

最新更新