export class Timer { private intervalHdl?: NodeJS.Timer; private subscribers: { [id: number]: { lastTick: number; seconds: number; tick: () => void; }; } = {}; private static INSTANCE?: Timer; public static get instance(): Timer { if (!Timer.INSTANCE) { Timer.INSTANCE = new Timer(); } return Timer.INSTANCE; } private constructor() {} public start() { if (this.intervalHdl) { return; } this.intervalHdl = setInterval(this.loop.bind(this), 1000); } private loop() { const now = new Date(); Object.values(this.subscribers).forEach(sub => { if (now.getTime() >= sub.lastTick + sub.seconds * 1000) { sub.lastTick = now.getTime(); sub.tick(); } }); } public subscribe(seconds: number, tick: () => void) { const lastTick = new Date().getTime(); const id = Object.keys(this.subscribers) .map(k => Number(k)) .reduce((r, id) => Math.max(r, id), 0) + 1; this.subscribers[id] = { lastTick, seconds, tick }; return id; } public unsubscribe(id: number) { if (typeof this.subscribers[id] === 'function') { delete this.subscribers[id]; } } public stop() { if (!this.intervalHdl) return; clearInterval(this.intervalHdl); this.intervalHdl = undefined; } }