Angular 11中RxJS timer实现的倒计时切换浏览器标签后停止如何解决?
问题根因
现代浏览器为了降低非活跃标签页的性能消耗,会对后台页面的定时器接口(setTimeout/setInterval,以及基于这两个接口封装的RxJS timer)执行节流策略:非活跃标签页的定时器回调最小执行间隔会被限制为1s,若页面长时间处于后台,间隔甚至会被拉长到数分钟。
你当前的实现依赖定时器每秒触发一次来让countdown减1,完全依赖定时器的触发频率计时,一旦定时器被节流触发频次降低,自然会出现倒计时走慢的问题。
修复方案
最稳妥且改造成本最低的方案是放弃依赖定时器触发频次计数,改用时间戳计算剩余时间,具体改造如下:
countdown: number = 59; countdownMapping: any = { '=9' : '0#', '=8' : '0#', '=7' : '0#', '=6' : '0#', '=5' : '0#', '=4' : '0#', '=3' : '0#', '=2' : '0#', '=1' : '0#', '=0' : '0#', 'other': '#' }; // 新增:存储倒计时结束时间戳 private countdownEndTime: number; resetResendTimer(clicked) { if (this.countdownActive === false) { this.countdownActive = true; if (clicked) { this.otherFunction(); } // 启动时记录60秒后的结束时间戳 this.countdownEndTime = Date.now() + 60 * 1000; timer(0, 1000) // 首次触发改为0,启动后立即计算一次剩余时间 .pipe( finalize(() => { this.endCountdown(); }), tap(() => { // 每次触发都用当前时间计算剩余秒数,不受定时器触发间隔影响 this.countdown = Math.ceil((this.countdownEndTime - Date.now()) / 1000); }), takeWhile(() => this.countdown > 0) ) .subscribe(); }
HTML部分逻辑不需要做任何修改,原有i18nPlural管道的格式化逻辑可以正常复用。
如果对倒计时精度要求更高,还可以搭配以下优化手段:
- 监听页面
visibilitychange事件,页面从后台切回前台时主动执行一次剩余时间计算,校正长时间后台导致的显示延迟 - 对于秒级以上的长倒计时,可将
timer的触发间隔拉长到2-3秒,进一步降低性能消耗
内容的提问来源于stack exchange,提问作者Terry Windwalker
相关产品推荐
相关产品推荐

