r-util-js/packages/common/src/timer/TimeoutTimer.ts

139 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

type TimerCallback = (time: number) => void;
/**
* 超时定时器
*
* 基于数值的倒计时器,从 startTime 递减到 endTime
* 每隔 interval 毫秒触发步骤监听器,到达 endTime 时触发完成监听器。
*
* 与 Countdown 不同的是TimeoutTimer 使用数值而非 dayjs duration
* 适合不需要格式化输出的纯数值倒计时场景。
*
* @example
* ```ts
* // 实例方式
* const timer = new TimeoutTimer(10, 0, 1000)
* timer.addStepEventListener((time) => console.log('剩余:', time))
* timer.addCountdownEventListener((time) => console.log('结束:', time))
* timer.start()
*
* // 静态工厂方式
* const timer2 = TimeoutTimer.start(10, 0, 1000,
* (time) => console.log('剩余:', time),
* (time) => console.log('结束:', time),
* )
* ```
*/
export default class TimeoutTimer {
/** 起始时间(数值) */
startTime = 0;
/** 结束时间(数值),倒计时到此值停止 */
endTime = 0;
/** 递减间隔(毫秒) */
interval = 0;
/** 当前剩余时间 */
time = 0;
/** 定时器 ID-1 表示未运行 */
id = -1;
/** 步骤监听器列表,每次递减时触发,参数为当前剩余时间 */
stepEventListenerList = <TimerCallback[]>[];
/** 完成监听器列表,倒计时结束时触发,参数为结束时间 */
countdownEventListenerList = <TimerCallback[]>[];
/**
* @param startTime 起始时间(数值)
* @param endTime 结束时间(数值),默认 0
* @param interval 递减间隔(毫秒),默认 1000
*/
constructor(startTime = 5, endTime = 0, interval = 1000) {
this.startTime = startTime;
this.endTime = endTime;
this.interval = interval;
}
/**
* 添加步骤监听器
*
* 每次递减时触发,参数为当前剩余时间
*
* @param cb 步骤回调函数,参数为当前时间(数值)
* @returns 若 cb 不是函数则返回 TypeError
*/
addStepEventListener(cb: TimerCallback) {
if (!(cb instanceof Function)) {
return new TypeError("回调函数类型错误: cb: " + cb);
}
this.stepEventListenerList.push(cb);
}
/**
* 添加完成监听器
*
* 倒计时到达 endTime 时触发,参数为结束时间
*
* @param cb 完成回调函数,参数为结束时间(数值)
* @returns 若 cb 不是函数则返回 TypeError
*/
addCountdownEventListener(cb: TimerCallback) {
if (!(cb instanceof Function)) {
return new TypeError("回调函数类型错误: cb: " + cb);
}
this.countdownEventListenerList.push(cb);
}
/**
* 静态工厂方法,创建并配置超时定时器
*
* @param startTime 起始时间(数值)
* @param endTime 结束时间(数值),默认 0
* @param interval 递减间隔(毫秒),默认 1000
* @param stepEventListener 步骤监听器(可选)
* @param countdownEventListener 完成监听器(可选)
* @returns 配置好的 TimeoutTimer 实例(需手动调用 start
*/
static start(
startTime: number,
endTime: number = 0,
interval = 1000,
stepEventListener?: TimerCallback,
countdownEventListener?: TimerCallback,
) {
const timer = new TimeoutTimer(startTime, endTime, interval);
if (stepEventListener != null) {
timer.addStepEventListener(stepEventListener);
}
if (countdownEventListener != null) {
timer.addCountdownEventListener(countdownEventListener);
}
return timer;
}
/**
* 开始倒计时,从 startTime 递减到 endTime到达后自动停止
*/
start() {
this.time = this.startTime;
this.id = window.setInterval(() => {
this.time -= this.interval;
console.log(this.time);
this.stepEventListenerList.forEach((cb) => cb(this.time));
if (this.time <= this.endTime && this.id !== -1) {
this.stop();
}
}, this.interval);
}
/**
* 停止倒计时,清除定时器并触发完成监听器
*/
stop() {
console.log("stop", this.id);
clearInterval(this.id);
this.id = -1;
this.time = this.endTime;
this.countdownEventListenerList.forEach((cb) => cb(this.time));
}
}