UNPKG

ts-time-utils

Version:

A comprehensive TypeScript utility library for time, dates, durations, and calendar operations with full tree-shaking support

222 lines (221 loc) 6.14 kB
/** * Async time utilities for delays, timeouts, and performance */ /** * Sleep for a specified number of milliseconds * @param ms - milliseconds to sleep */ export function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /** * Add a timeout to any promise * @param promise - promise to add timeout to * @param ms - timeout in milliseconds * @param timeoutMessage - optional timeout error message */ export function timeout(promise, ms, timeoutMessage = 'Operation timed out') { return Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject(new Error(timeoutMessage)), ms)) ]); } /** * Debounce function - delays execution until after delay has passed since last call * @param fn - function to debounce * @param delay - delay in milliseconds */ export function debounce(fn, delay) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn(...args), delay); }; } /** * Throttle function - limits execution to once per delay period * @param fn - function to throttle * @param delay - delay in milliseconds */ export function throttle(fn, delay) { let lastCall = 0; return (...args) => { const now = Date.now(); if (now - lastCall >= delay) { lastCall = now; fn(...args); } }; } /** * Retry a promise-returning function with exponential backoff * @param fn - function that returns a promise * @param maxAttempts - maximum number of attempts * @param baseDelay - base delay in milliseconds * @param maxDelay - maximum delay in milliseconds */ export async function retry(fn, maxAttempts = 3, baseDelay = 1000, maxDelay = 10000) { let lastError; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error; if (attempt === maxAttempts) { throw lastError; } // Exponential backoff with jitter const delay = Math.min(baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000, maxDelay); await sleep(delay); } } throw lastError; } /** * Stopwatch for measuring elapsed time */ export class Stopwatch { constructor() { this.startTime = null; this.endTime = null; this.pausedTime = 0; this.pauseStart = null; } /** * Start the stopwatch */ start() { if (this.startTime !== null) { throw new Error('Stopwatch is already running'); } this.startTime = performance.now(); this.endTime = null; this.pausedTime = 0; this.pauseStart = null; } /** * Stop the stopwatch */ stop() { if (this.startTime === null) { throw new Error('Stopwatch is not running'); } if (this.pauseStart !== null) { this.pausedTime += performance.now() - this.pauseStart; this.pauseStart = null; } this.endTime = performance.now(); const elapsed = this.endTime - this.startTime - this.pausedTime; return elapsed; } /** * Pause the stopwatch */ pause() { if (this.startTime === null) { throw new Error('Stopwatch is not running'); } if (this.pauseStart !== null) { throw new Error('Stopwatch is already paused'); } this.pauseStart = performance.now(); } /** * Resume the stopwatch */ resume() { if (this.pauseStart === null) { throw new Error('Stopwatch is not paused'); } this.pausedTime += performance.now() - this.pauseStart; this.pauseStart = null; } /** * Reset the stopwatch */ reset() { this.startTime = null; this.endTime = null; this.pausedTime = 0; this.pauseStart = null; } /** * Get elapsed time without stopping */ getElapsed() { if (this.startTime === null) { return 0; } const now = performance.now(); let pausedTime = this.pausedTime; if (this.pauseStart !== null) { pausedTime += now - this.pauseStart; } return now - this.startTime - pausedTime; } /** * Check if stopwatch is running */ isRunning() { return this.startTime !== null && this.endTime === null && this.pauseStart === null; } /** * Check if stopwatch is paused */ isPaused() { return this.pauseStart !== null; } } /** * Create a new stopwatch instance */ export function createStopwatch() { return new Stopwatch(); } /** * Measure execution time of a synchronous function * @param fn - function to measure * @returns tuple of [result, elapsed time in ms] */ export function measureTime(fn) { const start = performance.now(); const result = fn(); const elapsed = performance.now() - start; return [result, elapsed]; } /** * Measure execution time of an asynchronous function * @param fn - async function to measure * @returns promise that resolves to tuple of [result, elapsed time in ms] */ export async function measureAsync(fn) { const start = performance.now(); const result = await fn(); const elapsed = performance.now() - start; return [result, elapsed]; } /** * Benchmark a function by running it multiple times * @param fn - function to benchmark * @param iterations - number of iterations to run */ export function benchmark(fn, iterations = 1000) { const times = []; for (let i = 0; i < iterations; i++) { const [, elapsed] = measureTime(fn); times.push(elapsed); } const totalTime = times.reduce((sum, time) => sum + time, 0); const average = totalTime / iterations; const min = Math.min(...times); const max = Math.max(...times); return { totalTime, average, min, max, iterations, total: totalTime }; }