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

Rxjs实现定时请求并显示下次请求倒计时的技术问题

问题描述

开发一个支持按用户选择的x秒间隔自动更新的表格,请求依赖用户选择的筛选条件。核心要求:当用户选择10秒间隔并筛选某一天数据时,需在10秒后发起请求,必须等待响应完成后再重置定时器。

目前已实现定时请求逻辑,但无法显示下次请求的倒计时功能。现有服务端代码如下:

private dataIntervalSubject = new BehaviourSubject<number>(5);
private dataLoadingSubject = new BehaviourSubject<boolean>(false);
dataLoadingChanged$ = this.dataLoadingSubject.asObservable();

constructor(
    private globalFiltersService: GlobalFiltersService,
    private http: HttpClient
) {
    this.globalFiltersService.refreshIntervalSelectedAction$.subscribe(interval => {
        this.dataIntervalSubject.next(interval);
    });
}

dataTimer$ = this.dataIntervalSubject.pipe(
    switchMap(val => interval(val * 1000))
);

data$ = combineLatest(
    this.dataTimer$,
    this.globalFiltersService.dataSelectedAction$
).pipe(
    tap(() => this.dataLoadingSubject.next(true)),
    switchMap(([interval, date]) => this.http.get(`dataUrl/${date}`)
        .pipe(
            tap(() => this.dataLoadingSubject.next(false))
        )
    )
);

组件中使用async pipe的变量:

dataLoading$ = this.dataService.dataLoadingChanged$;
dataRequestTimeRemaining$ = this.dataService.dataTimer$;
data$ = this.dataService.data$;

当前dataRequestTimeRemaining$仅统计请求次数,无法实现倒计时,需调整代码实现该功能。

解决方案

核心思路是:创建一个可重置的倒计时流,在用户修改间隔、请求完成这两个时机重置倒计时;同时用倒计时结束的信号触发数据请求,确保请求完成后才重新开始倒计时。

步骤1:修改服务类代码

import { BehaviourSubject, Subject, interval, combineLatest } from 'rxjs';
import { switchMap, tap, map, takeWhile, last, repeat } from 'rxjs/operators';

private dataIntervalSubject = new BehaviourSubject<number>(5);
private dataLoadingSubject = new BehaviourSubject<boolean>(false);
private countdownReset$ = new Subject<void>(); // 用于触发倒计时重置

dataLoadingChanged$ = this.dataLoadingSubject.asObservable();
dataRequestTimeRemaining$ = this.createCountdownStream(); // 倒计时流

constructor(
    private globalFiltersService: GlobalFiltersService,
    private http: HttpClient
) {
    // 间隔变化时重置倒计时
    this.globalFiltersService.refreshIntervalSelectedAction$.subscribe(interval => {
        this.dataIntervalSubject.next(interval);
        this.countdownReset$.next();
    });
}

// 创建倒计时流:从当前间隔值开始每秒递减,直到0
private createCountdownStream() {
    return combineLatest([this.dataIntervalSubject, this.countdownReset$]).pipe(
        switchMap(([interval]) => {
            // 生成从interval到0的倒计时序列
            return interval(1000).pipe(
                map(i => interval - i),
                takeWhile(remaining => remaining >= 0),
                repeat() // 倒计时到0后,等待下一次重置信号
            );
        })
    );
}

// 修改数据请求流:用倒计时结束信号触发请求,请求完成后重置倒计时
data$ = combineLatest([
    this.dataRequestTimeRemaining$.pipe(last(remaining => remaining === 0)), // 倒计时到0时触发
    this.globalFiltersService.dataSelectedAction$
]).pipe(
    tap(() => this.dataLoadingSubject.next(true)),
    switchMap(([_, date]) => this.http.get(`dataUrl/${date}`).pipe(
        tap(() => {
            this.dataLoadingSubject.next(false);
            this.countdownReset$.next(); // 请求完成后重置倒计时
        })
    )),
    repeat() // 请求完成后,等待下一次倒计时结束信号
);

步骤2:组件中使用倒计时流

保持组件代码不变,dataRequestTimeRemaining$现在会每秒输出剩余秒数,直接用async pipe绑定到模板即可:

<p>下次请求剩余:{{ dataRequestTimeRemaining$ | async }} 秒</p>

关键逻辑说明

  • countdownReset$作为重置触发器,在间隔修改、请求完成时发出信号,确保倒计时从新的间隔值重新开始
  • createCountdownStream()生成的流每秒更新剩余秒数,直到0,然后等待下一次重置信号
  • data$通过监听倒计时到0的信号发起请求,请求完成后立即重置倒计时,严格符合"请求完成后再重置定时器"的要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:40:26