如何使用rxjs取消嵌套请求

问题描述 投票:1回答:3
buttonClicked$.pipe(
switchMap(value=>makeRequest1),
switchMap(responseOfRequest1=>makeRequest2))
.subscribe()

我需要按顺序发出2个http请求,并在按钮点击时中止下游待处理请求。以上代码是正确的方法吗?我知道新的点击将取消等待request1。如果点击发生在request2期间,request2也会被取消吗?

angular rxjs rxjs6
3个回答
1
投票

Why the second switchMap may not get cancelled

switchMap运算符仅在从上游Observable(即makeRequest1)接收下一个事件时取消其内部Observable,而不是在源Observable发出时(即buttonClicked$)。因此,请考虑以下事件序列:

first button click
first request 1 sent
first response to request 1 received
first request 2 sent
second button click
second request 1 sent
first response to request 2 received
second response to request 1 received

在这种情况下,因为在接收到对请求1的第二响应之前接收到对请求2的响应,即使在请求2完成之前发生第二按钮点击,也从未取消请求2。

如果请求1在请求2收到响应之前发出第二个响应,则取消请求2。但请注意,这不是取消它本身的按钮点击,而是取消它的请求1的发出。

The solution

如果您希望在单击按钮时可靠地取消这两个请求,则两个请求都需要在相同的switchMap内进行:

buttonClicked$.pipe(
  switchMap(clickValue => makeRequest1(clickValue).pipe(
    mergeMap(request1Value => makeRequest2(request1Value)))
).subscribe(request2Value => /* ... */);

1
投票

这是正确的行为,因为switchMap只有在收到next通知时才从其内部Observable取消订阅。这意味着当你有两个switchMaps时,第一个必须首先发出以触发第二个中的取消订阅。

您可以通过仅使用一个switchMap并将第二个makeRequest2调用与makeRequest1放入单个链中来避免这种情况。

buttonClicked$.pipe(
  switchMap(value => makeRequest1(value).pipe(
    mergeMap(responseOfRequest1 => makeRequest2(responseOfRequest1)),
  )),
  .subscribe()

这种方式当buttonClicked$发出它使switchMap取消订阅其内部Observable,内部取消订阅mergeMap将取消第二次调用,如果它仍然挂起。


0
投票

是的,它确实像间隔那样工作。我没有用网络请求测试它。

每次单击时,第二个可观察的间隔都会重新启动。

const { fromEvent, interval, of } = rxjs;
const { switchMap } = rxjs.operators;

const btn = document.getElementById('btn');
const result = document.getElementById('result');
const click$ = fromEvent(btn, 'click');

click$
	.pipe(
  	switchMap(value => of('Hello')),
  	switchMap(value => interval(1000))
  )
  .subscribe(
  	val => result.innerText = val
  )
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
<button id="btn">Click Me</button>

<div id="result"></div>
© www.soinside.com 2019 - 2024. All rights reserved.