取消之前的请求,只使用 redux observable 触发最新的请求 [英] Cancel previous requests and only fire the latest request with redux observable
问题描述
所以我有一个用例,我在移动地图时更新 api 请求 - 但它可能会生成几个带有小地图移动的快速请求 - 我想取消除最后一个之外的所有飞行请求.我可以使用 debounce 仅在延迟后发送请求.但是,如果它们碰巧仍在处理中,我仍然想取消任何旧请求.
So I have use case where I update the api request when the map is moved - but it could generate several rapid fire requests with small map movements - and I want to cancel all the inflight requests except for the last one. I can use debounce to only send requests after a delay. However I still want to cancel any old requests if they happen to still be in process.
const fetchNearbyStoresEpic = action$ =>
action$.ofType(FETCH_NEARBY_STORES)
.debounceTime(500)
.switchMap(action =>
db.collection('stores')
.where('location', '<=', action.payload.max).
.where('location', '>=', action.payload.min)
.map(response => fetchNearbyStoresFulfilled(response))
.takeUntil(action$.ofType(FETCH_STORES_CANCELLED))
);
我看到您可以使用 takeUntil
但您需要明确地触发取消操作.我在文档中看到 switchMap 将采用最新的并取消所有其他的 - 我是否必须在我的 api 调用中实现取消接口?在这种情况下,它将是对 firestore 的 firebase 查询.
I see that you can use takeUntil
but you need to explicitly fire a cancel action. I see in the docs that switchMap will take the latest and cancel all the others - do I have to implement a cancel interface in my api call? In this case it would be a firebase query to firestore.
推荐答案
因为它们有时间维度,所以有多种可观察的扁平化策略:
Because they have a time dimension, there are multiple flattening strategies for observables:
- 使用
mergeMap
(以flatMap
作为别名),接收到的 observable 被并发订阅,并且它们发出的值被扁平化到输出流中. - 使用
concatMap
,接收到的 observable 被排队并在每个完成时一个接一个订阅.(concatMap
是mergeMap
,并发为 1.) - 使用
switchMap
,当收到一个 observable 时,它会被订阅,而对之前收到的 observable 的任何订阅都将取消订阅. - 使用
exhaustMap
,当收到 observable 时,它会被订阅,除非订阅了之前收到的 observable 并且该 observable 尚未完成 - 在这种情况下,接收到的 observable 将被忽略.立>
- With
mergeMap
(which hasflatMap
as an alias), received observables are subscribed to concurrently and their emitted values are flattened into the output stream. - With
concatMap
, received observables are queued and are subscribed to one after the other, as each completes. (concatMap
ismergeMap
with a concurrency of one.) - With
switchMap
, when an observable is received it's subscribed to and any subscription to a previously received observable is unsubscribed. - With
exhaustMap
, when an observable is received it's subscribed to unless there is a subscription to a previously received observable and that observable has not yet completed - in which case the received observable is ignored.
所以,就像 Mark 在他的回答中所说的那样,当 switchMap
收到后续动作时,它将取消订阅任何未完成的请求.
So, like Mark said in his answer, when switchMap
receives a subsequent action, it will unsubscribe from any incomplete request.
但是,在去抖动的动作到达switchMap
之前,请求不会被取消.如果您想在另一次移动时立即取消任何挂起的请求 - 而不是等待去抖动持续时间 - 您可以使用 takeUntil
和 FETCH_NEARBY_STORES
操作:
However, the request won't be cancelled until the debounced action makes it to the switchMap
. If you want to cancel any pending requests immediately upon another move - rather than wait for the debounce duration - you can use takeUntil
with the FETCH_NEARBY_STORES
action:
const fetchNearbyStoresEpic = action$ =>
action$.ofType(FETCH_NEARBY_STORES)
.debounceTime(500)
.switchMap(action =>
db.collection('stores')
.where('location', '<=', action.payload.max).
.where('location', '>=', action.payload.min)
.map(response => fetchNearbyStoresFulfilled(response))
.takeUntil(action$.ofType(FETCH_NEARBY_STORES))
);
这应该会在另一次移动时立即取消订阅请求.(在我的脑海里,我想不起来 redux-observable
中 action$
的行为.你可能需要附加一个 skip(1)
到传递给 takeUntil
的 observable.试试看.)
That should effect the immediate unsubscription from a request upon another move. (Off the top of my head, I cannot recall the behaviour of action$
in redux-observable
. It's possible that you might need to append a skip(1)
to the observable passed to takeUntil
. Try it and see.)
而且,正如 Mark 所提到的,这是基于底层实现在取消订阅时取消请求.
And, as Mark mentioned, this is predicated on the underlying implementation cancelling the request upon unsubscription.
这篇关于取消之前的请求,只使用 redux observable 触发最新的请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!