📚 3 min read
Timer Management Examples ​
Learn how to effectively manage timers in asynchronous JavaScript applications.
Basic Usage ​
typescript
// Basic timer wrapper
class Timer {
private timerId: NodeJS.Timeout | null = null;
start(callback: () => void, delay: number): void {
this.stop();
this.timerId = setTimeout(callback, delay);
}
stop(): void {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
}
isRunning(): boolean {
return this.timerId !== null;
}
}
// Promise-based delay
const delay = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));
// Cancellable delay
const cancellableDelay = (ms: number) => {
let timeoutId: NodeJS.Timeout;
const promise = new Promise<void>((resolve) => {
timeoutId = setTimeout(resolve, ms);
});
return {
promise,
cancel: () => clearTimeout(timeoutId),
};
};
Advanced Patterns ​
Timer Manager ​
typescript
class TimerManager {
private timers = new Map<string, NodeJS.Timeout>();
setTimeout(id: string, callback: () => void, delay: number): void {
this.clearTimeout(id);
this.timers.set(
id,
setTimeout(() => {
this.timers.delete(id);
callback();
}, delay)
);
}
clearTimeout(id: string): void {
const timer = this.timers.get(id);
if (timer) {
clearTimeout(timer);
this.timers.delete(id);
}
}
clearAll(): void {
this.timers.forEach((timer) => clearTimeout(timer));
this.timers.clear();
}
hasTimer(id: string): boolean {
return this.timers.has(id);
}
get activeTimers(): number {
return this.timers.size;
}
}
Interval Manager ​
typescript
class IntervalManager {
private intervals = new Map<string, NodeJS.Timeout>();
private counters = new Map<string, number>();
setInterval(
id: string,
callback: () => void,
interval: number,
maxExecutions?: number
): void {
this.clearInterval(id);
this.counters.set(id, 0);
this.intervals.set(
id,
setInterval(() => {
const count = this.counters.get(id)! + 1;
this.counters.set(id, count);
if (maxExecutions && count >= maxExecutions) {
this.clearInterval(id);
}
callback();
}, interval)
);
}
clearInterval(id: string): void {
const interval = this.intervals.get(id);
if (interval) {
clearInterval(interval);
this.intervals.delete(id);
this.counters.delete(id);
}
}
clearAll(): void {
this.intervals.forEach((interval) => clearInterval(interval));
this.intervals.clear();
this.counters.clear();
}
getExecutionCount(id: string): number {
return this.counters.get(id) || 0;
}
}
Debounced Timer ​
typescript
class DebouncedTimer {
private timerId: NodeJS.Timeout | null = null;
private lastArgs: any[] = [];
constructor(
private callback: (...args: any[]) => void,
private delay: number
) {}
schedule(...args: any[]): void {
this.lastArgs = args;
if (this.timerId) {
clearTimeout(this.timerId);
}
this.timerId = setTimeout(() => {
this.callback(...this.lastArgs);
this.timerId = null;
}, this.delay);
}
cancel(): void {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
}
flush(): void {
if (this.timerId) {
clearTimeout(this.timerId);
this.callback(...this.lastArgs);
this.timerId = null;
}
}
}
Progressive Timer ​
typescript
interface ProgressiveTimerOptions {
initialDelay: number;
maxDelay: number;
factor: number;
onTick: () => void;
maxTicks?: number;
}
class ProgressiveTimer {
private currentDelay: number;
private timer: NodeJS.Timeout | null = null;
private tickCount = 0;
constructor(private options: ProgressiveTimerOptions) {
this.currentDelay = options.initialDelay;
}
start(): void {
this.stop();
this.scheduleNextTick();
}
private scheduleNextTick(): void {
if (this.options.maxTicks && this.tickCount >= this.options.maxTicks) {
return;
}
this.timer = setTimeout(() => {
this.tickCount++;
this.options.onTick();
this.currentDelay = Math.min(
this.currentDelay * this.options.factor,
this.options.maxDelay
);
this.scheduleNextTick();
}, this.currentDelay);
}
stop(): void {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
}
reset(): void {
this.stop();
this.currentDelay = this.options.initialDelay;
this.tickCount = 0;
}
}