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

React+RxJS轮询Epic:定时器结束触发指定Action的实现问询

Solution for Adding Timeout Action to Your Polling Epic

Great question! Let's fix that boundary case where your polling stops after 1 minute but doesn't dispatch any action. Here are three approaches tailored to different needs:

Approach 1: Quick Fix with endWith

If you don't need to distinguish between polling ending naturally (after 12 cycles) vs being manually stopped via POLL_STOP, use the endWith operator. This dispatches your desired action whenever the stream completes—whether from hitting the 12-cycle limit or receiving a POLL_STOP action.

const processPollEpic = action$ => action$.pipe(
  ofType(POLL_START),
  mergeMap(() => timer(0, 5000).pipe(
    exhaustMap(() => from(service.getSmth()).pipe(map(resp => {
      if (resp.isSuccess) {
        return processPollStop();
      }
      return processPollContinue();
    }))),
    takeUntil(action$.ofType(POLL_STOP)),
    take(12),
    // Dispatch your timeout action when the stream completes
    endWith(processPollTimeout()), // Replace with your actual timeout action creator
  )),
);

Approach 2: Distinguish Natural Timeout vs Manual Stop

If you only want the timeout action to fire when polling finishes all 12 cycles (not when manually stopped), we can track whether the stream was interrupted:

const processPollEpic = action$ => action$.pipe(
  ofType(POLL_START),
  mergeMap(() => {
    // Stream to track manual stop events
    const manualStop$ = action$.ofType(POLL_STOP);
    
    return timer(0, 5000).pipe(
      exhaustMap(() => from(service.getSmth()).pipe(map(resp => {
        if (resp.isSuccess) {
          return processPollStop();
        }
        return processPollContinue();
      }))),
      takeUntil(manualStop$),
      take(12),
      // Only append the timeout action if we didn't stop manually
      concatWith(
        of(processPollTimeout()).pipe(takeUntil(manualStop$))
      )
    );
  })
);

Approach 3: Strict 1-Minute Timeout (Most Accurate)

Your original take(12) assumes 12 cycles over 55 seconds (since timer(0,5000) fires immediately). For a strict 1-minute window (regardless of cycle count), use a dedicated timer for the timeout:

const processPollEpic = action$ => action$.pipe(
  ofType(POLL_START),
  mergeMap(() => {
    // Dispatch timeout action exactly after 1 minute
    const timeoutAction$ = timer(60000).pipe(map(() => processPollTimeout()));
    
    return merge(
      // Regular polling stream
      timer(0, 5000).pipe(
        exhaustMap(() => from(service.getSmth()).pipe(map(resp => {
          if (resp.isSuccess) {
            return processPollStop();
          }
          return processPollContinue();
        }))),
      ),
      // Timeout action stream
      timeoutAction$
    ).pipe(
      // Stop polling if we get POLL_STOP or the timeout action
      takeUntil(
        merge(action$.ofType(POLL_STOP), timeoutAction$)
      )
    );
  })
);

Key Notes:

  • endWith is ideal for simple cases where you just need an action on stream completion, no matter the reason.
  • The second approach ensures the timeout action only triggers when polling runs its full course without manual intervention.
  • The third approach avoids timing discrepancies from network delays, guaranteeing polling stops exactly at the 1-minute mark.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 08:52:49