[英]Angular, RxJS - How to cancel previous requests using switchMap?
[英]How to use RxJS to cancel previous HTTP Requests in an Angular Service
我知道有很多这样的问题,但它们经常让我感到困惑,或者让我很难将其应用于我的情况,所以我在这里问这样我就可以理解了。 在我的组件打字稿文件中,我有一个方法可以调用使用 http 返回 api 数据的服务,因此当用户单击界面上的芯片时,他们会调用以下内容..
fetchCounts(filters?: any): void {
this.loaded = false;
this.apiCall = this.api.getCounts(filters).subscribe((results: any) => {
// do something with the returned data
this.loaded = true;
this.apiCall.unsunscribe()
});
}
我的 api 服务如下所示:
getCounts(filters?: any): Observable<any> {
let params: any;
if (filters?.car?.length || filters?.bike?.length) {
params = this.addObjectToParams(new HttpParams(), filters);
}
return this.http.get('api/counts', { params } )
.pipe(map(this.extractData));
}
现在我注意到当用户单击我的界面添加和删除进行 API 调用的芯片时,由于过载/大量 API 调用,界面似乎不再显示真实数据。 因此,如果进行了新的调用(如果再次调用fetchCounts
),我想取消当前的 api/http 调用。 我试过在getCounts
方法中向 .pipe 添加去抖动,就像这样...... .pipe( debounceTime(500), map(this.extractData));
但它似乎没有做任何事情。 我想我必须添加一个switchMap
但是当我添加我的代码时,它会因为我缺乏理解而中断。 我目前正在浏览文档......但任何帮助将不胜感激。
在这种情况下,您可以使用unsubscribe
方法简单地取消订阅前一个调用。 当我们有一个高阶 observable 时使用switchMap
。
只需在拨打下一个电话之前取消订阅上一个电话。
fetchCounts(filters?: any): void {
this.loaded = false;
this.apiCall && this.apiCall.unsunscribe(); // Unsubscribe here as well.
this.apiCall = this.api.getCounts(filters).subscribe((results: any) => {
// do something with the returned data
this.loaded = true;
this.apiCall.unsunscribe();
});
}
如果您想避免处理订阅,您可以让一个主题为您管理所有这些。 这可能看起来像:
private _fetchCountsExe: Subject<any>;
constructor(){
this._fetchCountsExe = new Subject<any>();
this._fetchCountsExe.pipe(
tap(_ => this.loaded = false),
switchMap(filters => this.api.getCounts(filters))
).subscribe(results => {
// do something with the returned data
this.loaded = true;
});
}
fetchCounts(filters?: any): void {
this._fetchCountsExe.next(filters);
}
constructor()
的代码可以放在任何在服务初始化时运行的地方。 现在 switchMap 将完成取消旧订阅和切换到新订阅的所有工作。
这有很多好处。
其中最主要的是这种设计不依赖于 javascript 的事件循环来工作。 考虑这个取消订阅 observable 的简单示例:
const subscription = from([1,2,3,4]).subscribe(_ =>
subscription.unsubscribe();
);
这将永远失败。 因为这个 observable 是同步运行的,所以subscription
仍然是未定义的并且不能用于unsubscribe()
。
您当前的代码有一个隐藏的竞争条件,根据 Javascript 事件循环的工作方式,该条件对您有用。 但是,这会使您的代码变得脆弱。 例如,如果您决定(将来)缓存最近的值并在它们足够新鲜时立即返回它们,您的代码将意外中断。
这种方法还避免将订阅放在仅在一个函数中使用的全局范围内。 相反,您有一个描述操作的主题和一个初始化操作的函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.