取消之前的请求,只用 redux observable 触发最新的请求

Cancel previous requests and only fire the latest request with redux observable

所以我有一个用例,当地图移动时我更新 api 请求 - 但它可能会生成多个 rapid 小地图移动的开火请求 - 我想取消除最后一个请求外的所有机上请求。我可以使用 debounce 仅在延迟后发送请求。但是我仍然想取消任何旧的请求,如果它们恰好仍在处理中的话。

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 查询。

switchMap 将在通过它发送新发射时放弃其先前的可观察性。根据您的底层 HTTP 库,如果它支持取消(可观察到),这就足够了。

因为您的问题中没有提供实施细节,您将不得不查看 fetchNearbyStoresFulfilled 以查看它是否使用 Observable 感知的 http 客户端。如果它在内部使用承诺,则不提供取消支持。

来自 GitHub 问题中的 comment I made

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.

因此,正如 Mark 在他的回答中所说,当 switchMap 收到后续操作时,它将取消订阅任何未完成的请求。

但是,在去抖动作到达 switchMap 之前,请求不会被取消。如果您想在另一次移动后立即取消任何未决请求 - 而不是等待去抖持续时间 - 您可以使用 takeUntilFETCH_NEARBY_STORES 操作:

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))
    );

这应该会影响在另一个移动时立即取消订阅请求。 (我想不起来 action$redux-observable 中的行为。您可能需要将 skip(1) 附加到传递给 takeUntil 的可观察对象.试试看。)

并且,正如 Mark 所提到的,这是基于取消订阅时取消请求的基础实现。