From a comment I made in a GitHub issue:
Because they have a time dimension, there are multiple flattening strategies for observables:
- With
mergeMap
(which has flatMap
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
is mergeMap
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.
So, like Mark said in his answer, when switchMap
receives a subsequent action, it will unsubscribe from any incomplete request.
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))
);
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.)
And, as Mark mentioned, this is predicated on the underlying implementation cancelling the request upon unsubscription.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…