punctual-timer
v0.0.4
Published
A high-precision universal timer supporting browser, Node.js and mini-program environments
Maintainers
Readme
PunctualTimer
一个高精度通用定时器,支持浏览器、Node.js、小程序多环境运行。提供基础定时器功能以及高级任务编排、批量管理和高并发定时器池能力。
特性
核心特性
- 🎯 高精度计时:基于
requestAnimationFrame(浏览器)和高性能定时器(Node.js)实现 - 🌍 多环境兼容:自动检测运行环境并选择最优计时方案
- ✅ 浏览器(Chrome、Firefox、Safari、Edge)
- ✅ Node.js 14+
- ✅ 小程序(微信、支付宝、百度、字节、QQ)
- ✅ uni-app(App 端、H5、小程序)
- 🔄 丰富的生命周期:支持启动、暂停、恢复、停止、销毁等完整生命周期管理
- ⚡ 性能优化:智能降频、空闲休眠机制,降低功耗
- 📦 零依赖:纯 TypeScript 实现,无任何外部依赖
- 🔒 类型安全:完整的 TypeScript 类型定义
高级扩展功能
📋 任务编排能力(TaskScheduler)
- 延迟执行:支持任务延迟启动
- 失败重试:自定义重试策略和间隔
- 循环限制:控制任务最大执行次数
- 任务组合:支持任务链式调用和并行组
- 依赖关系:串行/并行执行模式,自动依赖解析
🎛️ 批量管理能力(TimerManager)
- 批量启停:一次性操作多个定时器
- 分组管理:按组和标签组织定时器
- 状态查询:批量获取定时器运行状态
- 灵活过滤:支持多种过滤条件组合
🚀 高并发支持(TimerPool)
- 定时器池:池化管理大量定时器实例
- 数量限制:防止资源耗尽的容量控制
- 自动清理:智能回收空闲和已销毁定时器
- 统计监控:实时跟踪使用情况和性能指标
- 内存优化:避免内存泄漏,支持数千至上万实例
安装
npm install punctual-timer
# 或
yarn add punctual-timer
# 或
pnpm add punctual-timer使用高级扩展
高级扩展模块需要单独安装(已包含在主包中):
# 使用基础定时器功能
import { PunctualTimer } from 'punctual-timer';
# 使用高级扩展功能(任务编排、批量管理、定时器池)
import { TaskScheduler, TimerManager, TimerPool } from 'punctual-timer/advanced';快速开始
基础用法
import { PunctualTimer } from 'punctual-timer';
// 创建定时器
const timer = new PunctualTimer({
fn: () => {
console.log('执行回调');
},
interval: 1000, // 1 秒
autoVisibility: true, // 页面隐藏时自动降频
});
// 启动定时器
timer.start();
// 暂停
timer.pause();
// 恢复
timer.resume();
// 停止并清理
timer.clear();高级功能
1. 任务编排(TaskScheduler)
import { TaskScheduler, createDelayedTask, createRetryableTask } from 'punctual-timer/advanced';
const scheduler = new TaskScheduler({
defaultMode: 'serial', // 默认串行执行
maxConcurrency: 5, // 最大并行数
onError: (id, err) => console.error(`任务 ${id} 失败:`, err),
});
// 添加延迟任务
scheduler.addTask({
id: 'delayed-task',
execute: () => console.log('延迟执行'),
delay: 2000, // 2 秒后执行
});
// 添加重试任务
scheduler.addTask({
id: 'retry-task',
execute: async () => {
const response = await fetch('/api/data');
return response.json();
},
retry: {
maxRetries: 3,
retryInterval: (attempt) => attempt * 1000, // 递增间隔
},
timeout: 5000, // 超时限制
});
// 创建任务链(自动建立依赖)
scheduler.chain(
{ id: 'init', execute: () => console.log('初始化') },
{
id: 'load',
execute: () => fetch('/api/load'),
retry: { maxRetries: 3, retryInterval: 1000 }
},
{ id: 'process', execute: (data) => console.log('处理:', data) },
{ id: 'cleanup', execute: () => console.log('清理') }
);
// 创建并行任务组
scheduler.parallel(
{ id: 'task1', execute: () => console.log('并行任务 1') },
{ id: 'task2', execute: () => console.log('并行任务 2') },
{ id: 'task3', execute: () => console.log('并行任务 3') }
);
// 启动调度器
await scheduler.start(); // 串行执行
// 或
await scheduler.start('parallel'); // 并行执行
// 获取任务状态
console.log(scheduler.getTaskStatus('init')); // 'completed'
// 暂停/恢复
scheduler.pause();
scheduler.resume();
// 取消特定任务
scheduler.cancelTask('task2');
// 清理已完成的任务
scheduler.cleanup();2. 批量管理(TimerManager)
import { TimerManager } from 'punctual-timer/advanced';
const manager = new TimerManager();
// 创建并注册定时器
manager.create('timer1', {
fn: () => console.log('Timer 1'),
interval: 1000,
}, { group: 'group-a', tags: ['important', 'monitor'] });
manager.create('timer2', {
fn: () => console.log('Timer 2'),
interval: 2000,
}, { group: 'group-a', tags: ['background'] });
manager.create('timer3', {
fn: () => console.log('Timer 3'),
interval: 3000,
}, { group: 'group-b', tags: ['critical'] });
// 批量启动(按分组)
manager.startAll({ group: 'group-a' });
// 批量启动(按标签)
manager.startAll({ tags: ['important'] });
// 全部暂停
manager.pauseAll();
// 全部恢复
manager.resumeAll({ group: 'group-a' });
// 批量修改间隔
manager.setIntervalAll(500, { group: 'group-b' });
// 批量停止并清理
manager.clearAll({ group: 'group-a' });
// 获取状态
console.log(manager.getStats());
// {
// total: 3,
// running: 2,
// paused: 1,
// stopped: 0,
// groups: { 'group-a': 2, 'group-b': 1 }
// }
// 获取运行中的数量
console.log(manager.getRunningCount()); // 2
// 获取所有 ID
console.log(manager.getAllIds({ group: 'group-a' })); // ['timer1', 'timer2']
// 从管理器中移除(不销毁定时器)
manager.unregister('timer3');
// 销毁管理器
manager.destroy();3. 定时器池(TimerPool)
import { TimerPool } from 'punctual-timer/advanced';
// 创建定时器池
const pool = new TimerPool({
maxSize: 10000, // 最大定时器数量
idleTimeout: 60000, // 空闲超时(毫秒)
cleanupInterval: 30000, // 清理检查间隔
});
// 获取单个定时器
const { id, timer } = pool.acquire({
fn: () => processItem(),
interval: 100,
})!;
timer.start();
// 批量获取定时器
const timers = pool.acquireBatch(1000, (index) => ({
fn: () => processItem(index),
interval: 100 + (index % 10) * 10, // 不同间隔
}));
// 启动所有定时器
timers.forEach(({ timer }) => timer.start());
// 释放单个定时器
pool.release(id);
// 批量释放
pool.releaseBatch(timers.map(t => t.id));
// 获取统计信息
const stats = pool.getStats();
console.log(stats);
// {
// totalCreated: 1001,
// activeTimers: 0,
// peakUsage: 1000,
// totalAcquired: 1001,
// totalReleased: 1001
// }
// 获取池状态
const status = pool.getStatus();
console.log(status);
// {
// size: 0,
// available: 10000,
// maxSize: 10000,
// utilizationRate: 0
// }
// 销毁池
pool.destroy();便捷工厂函数
import {
createDelayedTask,
createRetryableTask,
createLoopTask
} from 'punctual-timer/advanced';
// 创建延迟任务
const delayed = createDelayedTask(
() => console.log('延迟执行'),
5000, // 5 秒延迟
{ id: 'my-delayed-task' }
);
// 创建重试任务
const retryable = createRetryableTask(
async () => {
const res = await fetch('/api/data');
if (!res.ok) throw new Error('Failed');
},
3, // 最大重试 3 次
1000, // 重试间隔 1 秒
{ id: 'my-retry-task', timeout: 5000 }
);
// 创建循环任务
const loop = createLoopTask(
() => console.log('循环执行'),
1000, // 每 1 秒执行一次
10, // 最多执行 10 次
{ id: 'my-loop-task' }
);API 文档
核心类
PunctualTimer
基础定时器类,提供高精度计时功能。
构造函数选项:
构造函数支持两种调用方式:
方式一:使用配置对象(推荐)
const timer = new PunctualTimer({
fn: () => console.log('tick'),
interval: 1000,
onError: (err) => console.error(err),
autoVisibility: true,
maxCompensation: 10,
});方式二:使用参数列表(兼容旧版本)
const timer = new PunctualTimer(
() => console.log('tick'), // 回调函数
1000, // 间隔时间(毫秒)
(err) => console.error(err) // 错误处理(可选)
);配置选项详细说明:
fn: () => void- 定时回调函数interval: number- 执行间隔(毫秒),必须为大于 0 的有限数字onError?: (err: Error) => void- 错误处理回调(可选)autoVisibility?: boolean- 是否启用页面可见性自动暂停(默认 true)- 浏览器环境:页面隐藏时自动暂停,显示时自动恢复
- 小程序/uni-app App 端:此选项无效(不支持页面可见性 API)
- Node.js 环境:此选项无效
maxCompensation?: number- 最大补偿执行次数(默认 10)- 用于处理长时间阻塞后的补偿执行
- 防止定时器雪崩效应
- 例如:如果间隔 100ms,阻塞 500ms,最多执行 5 次(受 maxCompensation 限制)
主要方法:
start()- 启动定时器- 如果定时器已销毁会抛出错误
- 如果定时器已在运行会显示警告
- 如果定时器处于暂停状态会提示使用
resume()
pause(manual?: boolean)- 暂停定时器manual参数:是否为用户手动暂停(默认 true,内部使用)- 用于区分用户手动暂停和可见性自动暂停
resume(fromVisibility?: boolean)- 恢复定时器fromVisibility参数:是否由页面可见性触发(默认 false,内部使用)- 如果定时器是用户手动暂停的,不会响应可见性自动恢复
stop()- 停止定时器(可重新启动)- 重置所有状态,但可以再次调用
start()启动
- 重置所有状态,但可以再次调用
clear()- 销毁定时器- 完全释放所有资源,实例不能再使用
- 移除页面可见性事件监听
setInterval(interval: number)- 动态修改间隔- 修改后自动保持之前的运行状态(运行中/已暂停)
- 如果参数无效会抛出错误
getStatus()- 获取运行状态- 返回值:
{ isRunning: boolean; // 是否正在运行 isPaused: boolean; // 是否已暂停 isDestroyed: boolean; // 是否已销毁 hasStarted: boolean; // 是否曾经启动过(用于区分未启动和已停止) }
- 返回值:
static getEnvironment(): RuntimeEnv- 获取当前运行环境(静态方法)- 返回值:
'browser' | 'node' | 'miniprogram' | 'unknown'
- 返回值:
高级扩展模块
通过 punctual-timer/advanced 导入。
TaskScheduler
任务编排器,支持复杂的任务调度逻辑。
配置选项:
interface SchedulerConfig {
defaultMode?: 'serial' | 'parallel'; // 默认执行模式(默认 'serial')
maxConcurrency?: number; // 最大并行任务数(默认 10)
onError?: (taskId: string, error: Error) => void; // 全局错误处理回调
onTaskComplete?: (taskId: string) => void; // 单个任务完成回调
onAllComplete?: () => void; // 所有任务完成回调
}任务配置:
interface TaskConfig {
id: string; // 任务唯一标识
execute: () => void | Promise<void>; // 任务执行函数,支持同步或异步
delay?: number; // 延迟执行时间(毫秒)
interval?: number; // 执行间隔(毫秒),设置后将循环执行
maxIterations?: number; // 最大循环次数,0 表示无限循环(默认 1)
retry?: RetryStrategy; // 重试策略
timeout?: number; // 任务超时时间(毫秒)
dependencies?: string[]; // 依赖的任务 ID 列表
priority?: number; // 任务优先级,数字越大优先级越高(默认 0)
onComplete?: () => void; // 任务完成回调
onError?: (error: Error) => void; // 任务失败回调
onProgress?: (iteration: number, maxIterations: number) => void; // 任务进度回调
}重试策略:
interface RetryStrategy {
maxRetries: number; // 最大重试次数
retryInterval: number | ((attempt: number) => number); // 重试间隔,支持固定值或递增函数
continueOnMaxRetry?: boolean; // 达到最大重试次数后是否继续执行后续迭代(仅循环任务有效)
}主要方法:
addTask(config: TaskConfig)- 添加单个任务- 如果任务 ID 重复会抛出错误
- 返回
this支持链式调用
addTasks(configs: TaskConfig[])- 批量添加任务chain(...configs)- 创建任务链(自动建立串行依赖关系)- 后续任务自动依赖前一个任务
parallel(...configs)- 创建并行任务组(无依赖关系)start(mode?: ExecutionMode)- 启动调度- 返回 Promise,所有任务完成后 resolve
mode参数可覆盖默认执行模式
pause()- 暂停所有正在运行的任务resume()- 恢复所有已暂停的任务stop()- 停止调度器,取消所有进行中的任务cancelTask(taskId: string)- 取消特定任务- 返回
boolean表示是否成功取消
- 返回
getTaskStatus(taskId: string)- 获取任务状态- 返回值:
TaskStatus | null - TaskStatus 类型:
'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled'
- 返回值:
getAllStatus()- 获取所有任务状态- 返回
Map<string, TaskStatus>
- 返回
getSchedulerStatus()- 获取调度器运行状态- 返回:
{ isRunning: boolean; isPaused: boolean; taskCount: number }
- 返回:
cleanup()- 清理已完成/已取消/已失败的任务destroy()- 销毁调度器,释放所有资源
TimerManager
定时器批量管理器。
主要方法:
register(id, timer, options?)- 注册已有的定时器实例options:{ group?: string; tags?: string[]; metadata?: Record<string, unknown> }- 如果 ID 重复会抛出错误
- 返回
this支持链式调用
create(id, options, manageOptions?)- 创建并注册新定时器- 返回创建的
PunctualTimer实例
- 返回创建的
get(id)- 获取指定 ID 的定时器实例- 返回
PunctualTimer | undefined
- 返回
has(id)- 检查定时器是否已注册- 返回
boolean
- 返回
size- 获取注册的定时器总数(只读属性)startAll(filter?)/stopAll(filter?)- 批量启停定时器pauseAll(filter?)/resumeAll(filter?)- 批量暂停/恢复定时器clearAll(filter?)- 批量销毁定时器(并从管理器中移除)setIntervalAll(interval, filter?)- 批量修改定时器间隔getStatusAll(filter?)- 批量获取定时器状态- 返回
Map<string, TimerStatus>
- 返回
getRunningCount(filter?)- 获取正在运行的定时器数量getAllIds(filter?)- 获取所有定时器 ID(根据过滤条件)getGroupIds(group)- 获取指定分组的所有定时器 IDgetGroupNames()- 获取所有分组名称unregister(id)- 从管理器中移除定时器(不销毁定时器本身)- 返回被移除的
PunctualTimer实例,如果不存在返回undefined
- 返回被移除的
getStats()- 获取管理器统计信息- 返回:
{ total: number; // 总定时器数量 running: number; // 运行中的数量 paused: number; // 已暂停的数量 stopped: number; // 已停止的数量 groups: Record<string, number>; // 各分组的定时器数量 }
- 返回:
destroy()- 销毁管理器,清除并释放所有定时器
过滤条件:
interface TimerFilter {
ids?: string[];
group?: string;
tags?: string[];
status?: 'running' | 'paused' | 'stopped';
}TimerPool
定时器池,管理大量定时器实例。
配置选项:
interface PoolConfig {
maxSize?: number; // 最大定时器数量(默认 10000)
idleTimeout?: number; // 空闲超时时间(毫秒,默认 60000)
cleanupInterval?: number; // 清理检查间隔(毫秒,默认 30000)
defaultTimerOptions?: Partial<Omit<TimerOptions, 'fn' | 'interval'>>; // 定时器默认选项(fn 和 interval 需在 acquire 时提供)
}主要方法:
acquire(options: TimerOptions)- 从池中获取一个新定时器- 返回
{ id: string; timer: PunctualTimer } | null - 如果池已满返回
null - 如果池已销毁会抛出错误
- 返回
release(id: string)- 释放定时器回池(销毁定时器实例)- 返回
boolean表示是否释放成功
- 返回
acquireBatch(count: number, optionsFactory: (index: number) => TimerOptions)- 批量获取定时器- 返回成功获取的定时器列表(可能少于请求数量)
releaseBatch(ids: string[])- 批量释放定时器- 返回成功释放的数量
has(id)- 检查定时器是否在池中getTimer(id)- 获取池中的定时器实例- 返回
PunctualTimer | undefined
- 返回
getStats()- 获取池统计信息- 返回只读的
PoolStats对象:{ totalCreated: number; // 累计创建的定时器数量 activeTimers: number; // 当前活跃定时器数量 peakUsage: number; // 峰值使用量 totalAcquired: number; // 累计获取次数 totalReleased: number; // 累计释放次数 }
- 返回只读的
getStatus()- 获取池当前状态- 返回:
{ size: number; // 当前池大小 available: number; // 可用容量 maxSize: number; // 最大容量 utilizationRate: number; // 使用率(0-1) }
- 返回:
destroy()- 销毁定时器池,释放所有资源
类型导出
// 核心类型
import type { TimerOptions, TimerStatus } from 'punctual-timer';
// 高级类型
import type {
TaskStatus,
ExecutionMode,
RetryStrategy,
TaskConfig,
SchedulerConfig,
BatchResult,
PoolConfig,
PoolStats,
ManagedTimer,
TimerFilter,
} from 'punctual-timer/advanced';构建产物
项目生成以下构建文件:
核心库
dist/punctual-timer.esm.js- ES Module 版本(~4.0KB)dist/punctual-timer.cjs.js- CommonJS 版本(~4.1KB)dist/types/index.d.ts- TypeScript 类型声明
高级扩展模块
dist/punctual-timer-advanced.esm.js- ES Module 版本(~11.3KB)dist/types/advanced.d.ts- TypeScript 类型声明
注意:高级扩展模块将核心库作为外部依赖,不包含重复代码,需要同时安装主包。
使用示例
场景 0:uni-app 中使用
// 在 uni-app 项目中直接导入使用
import { PunctualTimer } from 'punctual-timer';
export default {
data() {
return {
timer: null as PunctualTimer | null,
count: 0
};
},
mounted() {
// 创建定时器
this.timer = new PunctualTimer({
fn: () => {
this.count++;
console.log('定时器执行次数:', this.count);
// uni-app API 调用
if (this.count % 10 === 0) {
uni.showToast({
title: `已执行${this.count}次`,
icon: 'none'
});
}
},
interval: 1000, // 每秒执行一次
autoVisibility: false, // uni-app App 端不支持页面可见性 API
});
// 启动定时器
this.timer.start();
},
beforeDestroy() {
// 组件销毁时清理定时器
if (this.timer) {
this.timer.clear();
this.timer = null;
}
}
};注意: uni-app App 端的特殊说明
- ✅ 支持 iOS/Android App
- ✅ 支持 H5 模式
- ✅ 支持编译到各小程序平台
- ⚠️
autoVisibility选项在 App 端无效(因为没有页面可见性 API) - 💡 建议使用 uni-app 的生命周期钩子管理定时器
场景 1:数据同步任务
import { TaskScheduler } from 'punctual-timer/advanced';
const scheduler = new TaskScheduler({
defaultMode: 'serial',
onError: (id, err) => console.error(`${id} 失败:`, err),
});
// 数据同步流程
scheduler.chain(
{
id: 'prepare',
execute: () => {
console.log('准备同步数据...');
}
},
{
id: 'fetch-local',
execute: async () => {
const data = await fetch('/api/local-data');
return data.json();
},
retry: { maxRetries: 3, retryInterval: 2000 }
},
{
id: 'fetch-remote',
execute: async () => {
const data = await fetch('/api/remote-data');
return data.json();
},
retry: { maxRetries: 5, retryInterval: 3000 }
},
{
id: 'merge-data',
execute: (local, remote) => {
console.log('合并数据...');
}
},
{
id: 'upload',
execute: async () => {
await fetch('/api/upload', { method: 'POST' });
},
timeout: 10000
},
{
id: 'cleanup',
execute: () => {
console.log('清理临时数据');
}
}
);
// 启动同步流程
await scheduler.start();场景 2:监控系统定时器管理
import { TimerManager } from 'punctual-timer/advanced';
const manager = new TimerManager();
// 创建监控定时器
manager.create('cpu-monitor', {
fn: () => monitorCPU(),
interval: 5000,
}, { group: 'monitors', tags: ['system', 'critical'] });
manager.create('memory-monitor', {
fn: () => monitorMemory(),
interval: 5000,
}, { group: 'monitors', tags: ['system'] });
manager.create('network-monitor', {
fn: () => monitorNetwork(),
interval: 10000,
}, { group: 'monitors', tags: ['network'] });
manager.create('log-flush', {
fn: () => flushLogs(),
interval: 30000,
}, { group: 'maintenance', tags: ['logging'] });
// 启动所有监控
manager.startAll({ group: 'monitors' });
// 获取所有运行中的监控器
console.log(manager.getStatusAll({
group: 'monitors',
status: 'running'
}));
// 系统维护时暂停所有监控
manager.pauseAll();
// ... 执行维护操作 ...
// 恢复监控
manager.resumeAll();场景 3:高并发数据处理
import { TimerPool } from 'punctual-timer/advanced';
const pool = new TimerPool({
maxSize: 5000,
idleTimeout: 120000,
});
// 处理 10000 个数据项
const BATCH_SIZE = 500;
const TOTAL_ITEMS = 10000;
for (let i = 0; i < TOTAL_ITEMS; i += BATCH_SIZE) {
// 批量获取定时器
const timers = pool.acquireBatch(BATCH_SIZE, (idx) => ({
fn: () => {
const itemIndex = i + idx;
processData(items[itemIndex]);
},
interval: 100 + (idx % 20) * 5, // 错开执行时间
}));
// 启动定时器
timers.forEach(({ timer }) => timer.start());
// 等待一批完成后释放
setTimeout(() => {
pool.releaseBatch(timers.map(t => t.id));
}, 5000);
}
// 监控池使用情况
setInterval(() => {
const stats = pool.getStats();
console.log(`活跃定时器:${stats.activeTimers}, 峰值:${stats.peakUsage}`);
}, 1000);最佳实践
1. 任务编排
- 合理设置超时:为异步任务设置合适的
timeout,避免任务卡死 - 使用重试策略:对网络请求等可能失败的任务配置
retry - 任务链 vs 并行:有依赖关系的任务使用
chain(),独立任务使用parallel() - 优先级控制:通过
priority字段控制任务执行顺序
2. 批量管理
- 分组管理:使用
group将相关定时器归类,便于批量操作 - 标签标记:使用
tags标记定时器特性(如critical,background) - 定期清理:不再使用的定时器及时调用
clearAll()释放
3. 定时器池
- 合理设置上限:根据系统资源设置合适的
maxSize - 监控使用率:定期调用
getStats()监控池使用情况 - 及时释放:使用完毕的定时器立即调用
release()或releaseBatch() - 利用自动清理:配置合适的
idleTimeout让池自动回收空闲定时器
4. 性能优化
- 避免过多定时器:单个页面建议不超过 1000 个活跃定时器
- 使用定时器池:需要大量定时器时优先使用
TimerPool - 合理设置间隔:避免过短的 interval(如 < 10ms)造成性能压力
- 及时清理:组件卸载时调用
destroy()彻底释放资源
注意事项
环境兼容性
- 浏览器:支持现代浏览器(Chrome、Firefox、Safari、Edge)
- Node.js:支持 Node.js 14+
- 小程序:支持微信小程序、支付宝小程序、百度小程序、字节小程序、QQ 小程序
- uni-app:
- ✅ App 端(iOS/Android)
- ✅ H5 端
- ✅ 各小程序平台
- ⚠️
autoVisibility选项在 App 端无效(无页面可见性 API) - 💡 建议在
mounted中启动,beforeDestroy中清理
内存管理
- 使用完毕后务必调用
clear()或destroy()释放资源 - 长时间运行的应用建议定期检查定时器状态
- 避免在循环中无限制创建定时器而不释放
异步任务处理
execute函数可以是异步的(返回 Promise)- 异步任务失败会触发
onError回调 - 配置
timeout可以防止异步任务无限期挂起
