You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RxJS去除重复请求:如何避免获取帖子时重复请求同一用户?

Avoiding Duplicate User Requests in Redux-Observable Epic

Great question—redundant API calls are a common pitfall, and your existing code already has the first piece of the puzzle (checking the cache). To fully prevent duplicate requests (including in-flight ones), we need to track ongoing requests so we don’t fire a new call while one’s already in progress for the same user.

Here’s how to modify your Epic to handle both cached users and pending requests:

// Track pending user fetch requests (persists across Epic calls since Epics are singletons)
const pendingRequests = new Map();

const fetchUserEpic = (action$, store) => action$
  .ofType(UsersActions.FETCH_USER)
  .mergeMap(action => {
    const userId = action.payload;
    const users = store.getState().usersStore.get('users').toJS();

    // 1. Check if user is already cached in the store
    if (users[userId]) {
      // Return action indicating we're using cached data (include userId for context)
      return of(UsersActionCreators.loadCachedUser(userId));
    }

    // 2. Check if there's already an in-flight request for this userId
    if (pendingRequests.has(userId)) {
      // Reuse the existing pending observable instead of making a new API call
      return pendingRequests.get(userId);
    }

    // 3. No cache or pending request—initiate the API call
    const userFetch$ = ajax.getJSON(`/api/users/${userId}`)
      .map(userData => UsersActionCreators.fetchUserSuccess(userData))
      .catch(error => of(UsersActionCreators.fetchUserFailure(userId, error)))
      .finally(() => {
        // Clean up: remove the request from pending once it completes (success/error)
        pendingRequests.delete(userId);
      });

    // Add the ongoing request to our tracking map
    pendingRequests.set(userId, userFetch$);

    return userFetch$;
  });

Key Improvements Explained:

  • Pending Request Tracking: The pendingRequests Map keeps tabs on all in-progress API calls by userId. This ensures we don’t send duplicate requests while one’s already underway.
  • Cache Check First: We still prioritize the store cache to avoid unnecessary network calls entirely if the user data is already available.
  • Reuse In-Flight Observables: If a request is already pending for a userId, we return that existing observable instead of creating a new one. This means any subscribers to the action will receive the result of the ongoing request once it finishes.
  • Cleanup: The finally block ensures we remove completed requests from the map, so future actions can trigger a new request if needed (e.g., retrying after a failed call).

Bonus Notes:

  • Make sure your loadCachedUser action includes the userId so your reducer knows which user to mark as cached (if needed).
  • If you’re using TypeScript, you can type the pendingRequests Map to enforce userId types and observable types for better type safety.

内容的提问来源于stack exchange,提问作者Eyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:49:55