繁体   English   中英

如何在 Angular 服务中使用 RxJS 取消之前的 HTTP 请求

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM