@oxog/delay
Version:
A comprehensive, zero-dependency delay/timeout utility library with advanced timing features
109 lines • 4.19 kB
JavaScript
import { DelayError, DelayErrorCode } from '../types/index.js';
import { validateDelay } from '../utils/validation.js';
import { getHighResolutionTime } from '../utils/time.js';
export function createBasicDelay(ms, options = {}) {
validateDelay(ms);
return new Promise((resolve, reject) => {
const { signal, onProgress, progressInterval = 100 } = options;
// Check if already aborted
if (signal?.aborted) {
reject(new DelayError('Delay was aborted', DelayErrorCode.CANCELLED));
return;
}
// Handle immediate resolve for zero delay (but still check for cancellation)
if (ms === 0) {
// Use setTimeout to allow for cancellation even on zero delay
const timeoutId = setTimeout(() => {
if (!signal?.aborted) {
resolve();
}
}, 0);
signal?.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new DelayError('Delay was cancelled', DelayErrorCode.CANCELLED));
});
return;
}
const startTime = getHighResolutionTime();
let timeoutId;
let progressIntervalId;
let isResolved = false;
const cleanup = () => {
if (typeof timeoutId === 'number') {
clearTimeout(timeoutId);
}
else {
clearTimeout(timeoutId);
}
if (progressIntervalId !== undefined) {
if (typeof progressIntervalId === 'number') {
clearInterval(progressIntervalId);
}
else {
clearInterval(progressIntervalId);
}
}
};
const handleAbort = () => {
if (!isResolved) {
isResolved = true;
cleanup();
reject(new DelayError('Delay was cancelled', DelayErrorCode.CANCELLED));
}
};
const handleResolve = () => {
if (!isResolved) {
isResolved = true;
cleanup();
signal?.removeEventListener('abort', handleAbort);
resolve();
}
};
// Set up abort handling
signal?.addEventListener('abort', handleAbort);
// Set up progress tracking
if (onProgress && ms > progressInterval) {
const updateProgress = () => {
if (!isResolved) {
const elapsed = getHighResolutionTime() - startTime;
const clampedElapsed = Math.min(elapsed, ms);
onProgress(clampedElapsed, ms);
if (elapsed >= ms) {
if (progressIntervalId !== undefined) {
if (typeof progressIntervalId === 'number') {
clearInterval(progressIntervalId);
}
else {
clearInterval(progressIntervalId);
}
}
}
}
};
progressIntervalId = setInterval(updateProgress, progressInterval);
// Call immediately for initial progress
updateProgress();
}
// Set the main timeout
timeoutId = setTimeout(handleResolve, ms);
});
}
export function createProgressiveDelay(ms, onProgress, progressInterval = 100) {
return createBasicDelay(ms, { onProgress, progressInterval });
}
export function msDelay(milliseconds, options) {
return createBasicDelay(milliseconds, options);
}
export function secondsDelay(seconds, options) {
return createBasicDelay(seconds * 1000, options);
}
export function minutesDelay(minutes, options) {
return createBasicDelay(minutes * 60 * 1000, options);
}
export function hoursDelay(hours, options) {
return createBasicDelay(hours * 60 * 60 * 1000, options);
}
export function daysDelay(days, options) {
return createBasicDelay(days * 24 * 60 * 60 * 1000, options);
}
//# sourceMappingURL=delay.js.map