【问题标题】:Observables : Cancel previous http request on new subscription callObservables : 在新的订阅调用中取消之前的 http 请求
【发布时间】:2018-11-22 13:30:11
【问题描述】:

我正在为我的项目开发搜索功能。一旦用户在搜索栏上输入任何内容;在搜索文本发生任何变化时,我会将文本发送到后端进行验证并接收响应(文本中有错误或没有错误):

this.searchBar.on('change', () => {

    http.post('api_link', {searchText: 
       this.serachBar.searchText}).subscribe(resp => {
            this.resp = resp['Result'];
       });
    })

现在,随着用户不断在搜索栏中输入内容,多个验证响应会通过后端传入。但是,对于任何新的更改,只有最新的订阅有效,之前对 api 的任何调用都是无用的。

有什么方法可以取消之前使用订阅对 api 的任何新调用的订阅?

注意:似乎可以只等待所有响应,但我还将在搜索栏下方显示响应(在此之前显示加载器)。因此,与其在各种响应状态之间转换,我希望加载器继续加载直到最新响应可用。

【问题讨论】:

  • 查看 switchMap 并去抖动。
  • 您可以使用unsubscribe() 订阅每个新更改。这样旧的http请求将被取消,只有最新的subscription有效
  • 一个很好的资源,可以在未来帮助你:learnrxjs.io

标签: angular rxjs httprequest observable subscribe


【解决方案1】:

我会使用一个主题来保持一切都是被动的。在您的模板 html 中侦听更改事件并向主题发出新值。

 <searchBar (change)="search$.next($event.target.value)" />

然后在你的组件中:

  this.subscription = this.search$.pipe(
     debounceTime(800), 
     distinctUntilChanged(),
     switchMap(searchText=>http.post('api_link', {searchText})
    }).subscribe(response=>{
       this.response = response.
    });

如果通过主题发出新值,switchMap 将取消任何尚未完成的 HTTP 请求。您可以使用 debouneTime 来查看适合您的感觉。最后,请确保您在 ngOnDestroy 中取消订阅您的主题,这将阻止任何内存链接并保持一切正常。:

ngOnDestroy(){
   this.subscription.unsubscribe();
}

Suresh 的answer 有一个distinctUntilChanged(),这是对解决方案的极好补充。我正在添加它,但想在下面感谢他的回答。这是一个好处,因为如果我搜索 egg 就会发出请求。但随后我在 egg 的末尾添加了一个s 并在去抖完成之前改变了主意,另一个重复的 HTTP 帖子将不会搜索 egg。

【讨论】:

  • 实际上我的元素是在打字稿中动态创建的,所以我无法在模板中添加更改事件监听器。仅在 ts 中执行此操作的方法是什么? (如问题中所述,我在 ts 中有一个更改事件侦听器)
  • @VSharma 这可能超出了原始问题的范围。但是,您如何动态创建元素?
  • 如果您的代码中有搜索栏类,您可以直接订阅更改事件发射器。所以:this.searchBar.change.pipe( 而不是 this.search$.pipe( 这是因为 Angular 的 Event Emitter 扩展了 RxJS 的 Subject。我以为我曾经读过 Angular 团队不建议直接订阅 Event Emitters。但我可能弄错了,您可能需要四处挖掘以确认这一点。这不是我通常遇到的情况,所以我不必担心。
  • 我们可以在拦截器中这样做吗?
【解决方案2】:

您需要使用 debounceTime 和 switchMap 运算符。

this.searchBar.on('change', () => {

    of(this.serachBar.searchText).pipe(
       debounceTime(400),
       distinctUntilChanged(),
       switchMap((text)=> {
          return http.post('api_link', {searchText: text}).map(resp => {
            return resp['Result'];
          });
        });
    ).subscribe(response=> console.log(response));

});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 2020-10-28
    相关资源
    最近更新 更多