【问题标题】: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 }));
}