如何取消RxJS delayWhen中的interval以避免页面返回后出现并行重复的刷新任务?
解决NgRx Effect中页面切换后重复刷新的问题
这个问题我之前也碰到过,核心原因就是页面跳转后,旧的Effect流并没有被彻底清理——delayWhen里的interval定时器还在后台默默等待触发,等你返回主页时,新的流又启动了,新旧两个流并行运行,自然就出现了每10秒刷两次的异常。
下面是具体的解决思路和修改方案:
1. 先定义页面切换的Action
你需要新增两个自定义Action:
LeaveHomepageAction:跳转到其他页面时触发EnterHomepageAction:进入主页时触发
这两个Action用来标记页面的切换状态,方便我们控制Effect的生命周期。
2. 修改刷新Effect,加入流终止逻辑
利用RxJS的takeUntil操作符,监听LeaveHomepageAction,一旦触发就立即终止当前的Effect流,包括正在等待的interval和正在进行的HTTP请求:
refresh$ = createEffect(() => { return this.actions$.pipe( ofType(HomepageActions.RefreshSuccessAction), // 监听离开主页的Action,触发时直接终止当前流 takeUntil(this.actions$.pipe(ofType(HomepageActions.LeaveHomepageAction))), delayWhen(() => interval(10000)), switchMap(() => { console.log(this.retriesLeft, Date().toLocaleString()) if (!this.retriesLeft) { return of(HomepageActions.RefreshIsOverAction()); } this.retriesLeft--; return this.refreshService.getFreshData().pipe( map((data: PagingResponse<Data>) => { return HomepageActions.RefreshSuccessAction({payload: data}); }), catchError((error: Error) => { return of(new GenericErrorAction(error)); }), // 确保请求过程中离开主页时,也能取消请求 takeUntil(this.actions$.pipe(ofType(HomepageActions.LeaveHomepageAction))) ); }) ); });
3. 重置重试计数器
每次进入主页时,要把retriesLeft重置为初始值(10),避免上次的计数影响新的刷新循环。可以新增一个Effect来处理:
initRefreshRetry$ = createEffect(() => { return this.actions$.pipe( ofType(HomepageActions.EnterHomepageAction), tap(() => { this.retriesLeft = 10; // 重置为初始的10次重试次数 }) ); }, { dispatch: false }); // 不需要分发新Action,所以设置dispatch为false
为什么这个方案有效?
takeUntil操作符会在目标Observable(这里是LeaveHomepageAction的流)发出值时,立即完成当前的Observable流:
- 跳转到其他页面时,
LeaveHomepageAction触发,旧的Effect流被彻底终止,delayWhen里的interval定时器也会被清理,不会再后台等待。 - 返回主页时,新的
RefreshSuccessAction会启动全新的Effect流,此时只有一个定时器在运行,不会出现并行刷新的情况。 - 给HTTP请求也加上
takeUntil,还能避免页面离开后请求仍在后台运行,减少不必要的资源消耗。
内容的提问来源于stack exchange,提问作者tson khai hoi
相关产品推荐
相关产品推荐

