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

Angular RxJS并发倒计时重启异常:API重复调用及循环调用问题排查

问题排查与解决方案

核心问题分析

  1. 重复API调用:每个事件的倒计时订阅独立判断自身timer是否归0,一旦满足条件就调用getEvents。如果有多个事件同时结束,就会触发多次API请求;且旧订阅未在刷新前取消,会继续触发后续调用。
  2. 订阅泄漏与无限循环:单个Subject管理所有订阅的方式存在漏洞,调用getEvents后会创建新的订阅和Subject,旧订阅若未被正确终止,会持续操作旧的事件数据,导致timer归0后再次触发刷新,形成无限循环。

修正后的代码

// helper.service.ts
import { Subscription, timer } from 'rxjs';

// 存储所有倒计时订阅
private countdownSubs: Subscription[] = [];
// 防止重复调用API的锁
private isRefreshing = false;

getCounter() {
    return timer(0, 1000);
}

getEvents() {
    // 避免并发刷新
    if (this.isRefreshing) return;
    
    const url = '/app/events';
    this.isRefreshing = true;
    
    this.auth.get(url).then(x => {
        this.eventArr = x?.data.events || [];
        // 先清除旧订阅,再创建新的倒计时
        this.clearCountdownSubs();
        this.showTimer();
    }).catch(err => {
        console.log(err);
    }).finally(() => {
        // 释放刷新锁
        this.isRefreshing = false;
    });
}

// 统一清除所有倒计时订阅
private clearCountdownSubs() {
    this.countdownSubs.forEach(sub => sub.unsubscribe());
    this.countdownSubs = [];
}

showTimer() {
    if (this.eventArr.length === 0) return;
    
    // 初始化每个事件的剩余秒数,避免负数
    this.eventArr.forEach(x => {
        const dateFuture = x?.inaugurateDt * 1000;
        const now = new Date().getTime();
        const t = dateFuture - now;
        x.timer = Math.max(Math.floor(t / 1000), 0);
    });
    
    // 单个timer统一更新所有事件的倒计时,减少订阅开销
    const sub = this.getCounter().subscribe(() => {
        let needRefresh = false;
        
        this.eventArr.forEach(x => {
            if (x.timer > 0) {
                x.timer--;
            }
            // 标记是否需要刷新事件
            if (x.timer === 0) {
                needRefresh = true;
            }
        });
        
        if (needRefresh) {
            this.clearCountdownSubs();
            this.getEvents();
        }
    });
    
    this.countdownSubs.push(sub);
}

关键修优点说明

  • 统一订阅管理:用countdownSubs数组存储所有倒计时订阅,每次刷新事件前强制清除旧订阅,彻底避免旧逻辑干扰新数据。
  • 刷新锁机制:isRefreshing变量确保同一时间只有一次API请求,从根源解决重复调用问题。
  • 全局timer优化:单个timer更新所有事件的倒计时,减少RxJS订阅数量,提升性能的同时简化逻辑。
  • 负数防护:用Math.max确保timer不会出现负数,避免无意义的刷新触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:01:22