【问题标题】:switchMap doesn't cancel previous http requestswitchMap 不会取消之前的 http 请求
【发布时间】:2018-11-17 20:11:33
【问题描述】:

switchMap 不会取消之前的 http 请求。也尝试使用exhaustMap,但没有帮助。这是相同的要点https://gist.github.com/saiumesh-letznav/a33ac54444ba707b9dbb172271b518fe

import { Subject } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import Axios from 'axios';

const baseUrl =
  'https://api.github.com/search/repositories?q=golang+language:go&sort=stars&order=desc';

class GitService {
  private $obs: Subject<void> = new Subject();

  constructor() {
    this.$obs
      .pipe(switchMap((_) => Axios.get(baseUrl)))
      // tslint:disable-next-line:no-console
      .subscribe((res) => console.log({ res }));
  }

  public getGOlangRepos() {
    this.$obs.next();
  }
}

const instance = new GitService();

instance.getGOlangRepos();
instance.getGOlangRepos();
instance.getGOlangRepos();
instance.getGOlangRepos();

【问题讨论】:

    标签: javascript typescript rxjs


    【解决方案1】:

    如果你想真正取消 axios 请求(而不是让它继续但忽略它的结果),那么你不能简单地 switchmap 到 axios.get 返回的承诺。 Promise 是不可取消的,虽然 axios 确实支持取消,但 rxjs 不知道 axios 的取消是如何工作的。所以你需要自己实现取消。

    在 rxjs 之外,您可以通过以下方式发出 axios 请求,然后稍后将其取消:

    const cancelToken = Axios.CancelToken.source();
    const promise = Axios.get(someUrl, { cancelToken: cancelToken.token };
    
    // ... then later to cancel it:
    cancelToken.cancel();
    

    如果你希望 rxjs 能够使用这个取消逻辑,你需要创建一个自定义的 observable。如果这是你认为你会经常做的事情,我建议你把它移到一个辅助函数中。像这样的:

    function getAsObservable(url) {
      return Observable.create(function(observer) {
        const cancelToken = Axios.CancelToken.source();
        Axios.get(url, { cancelToken: cancelToken.token })
          .then(result => {
            observer.next(result);
            observer.complete();
          }, err => {
            if (axios.isCancel(err)) {
              observer.complete();
            } else {
              observer.error(err);
            }
          })
    
        return () => cancelToken.cancel();
      });
    }
    

    然后你的代码可以变成:

    this.$obs
     .pipe(switchMap((_) => getAsObservable(baseUrl)))
     .subscribe((res) => console.log({ res }));
    

    【讨论】:

      【解决方案2】:

      您可以通过使用debounceTime 避免多次http 调用,以便在进行http 调用之前添加延迟。一旦发起http调用,即使在客户端取消订阅,服务器也会继续处理。

      例如 - 下面的代码将等待 500 毫秒,然后再进行 http 调用。

      constructor() {
       this.$obs
        .pipe(
           debounceTime(500),
           switchMap((_) => Axios.get(baseUrl))
        )
        // tslint:disable-next-line:no-console
        .subscribe((res) => console.log({ res }));
      }
      

      【讨论】:

        猜你喜欢
        • 2019-05-25
        • 2013-08-03
        • 2018-12-09
        • 2016-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-17
        相关资源
        最近更新 更多