buttonClicked$.pipe(
switchMap(value=>makeRequest1),
switchMap(responseOfRequest1=>makeRequest2))
.subscribe()
我需要按顺序发出2个http请求,并在按钮点击时中止下游待处理请求。以上代码是正确的方法吗?我知道新的点击将取消等待request1
。如果点击发生在request2
期间,request2
也会被取消吗?
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的发出。
如果您希望在单击按钮时可靠地取消这两个请求,则两个请求都需要在相同的switchMap
内进行:
buttonClicked$.pipe(
switchMap(clickValue => makeRequest1(clickValue).pipe(
mergeMap(request1Value => makeRequest2(request1Value)))
).subscribe(request2Value => /* ... */);
这是正确的行为,因为switchMap
只有在收到next
通知时才从其内部Observable取消订阅。这意味着当你有两个switchMap
s时,第一个必须首先发出以触发第二个中的取消订阅。
您可以通过仅使用一个switchMap
并将第二个makeRequest2
调用与makeRequest1
放入单个链中来避免这种情况。
buttonClicked$.pipe(
switchMap(value => makeRequest1(value).pipe(
mergeMap(responseOfRequest1 => makeRequest2(responseOfRequest1)),
)),
.subscribe()
这种方式当buttonClicked$
发出它使switchMap
取消订阅其内部Observable,内部取消订阅mergeMap
将取消第二次调用,如果它仍然挂起。
是的,它确实像间隔那样工作。我没有用网络请求测试它。
每次单击时,第二个可观察的间隔都会重新启动。
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>