@oxog/delay
Version:
A comprehensive, zero-dependency delay/timeout utility library with advanced timing features
129 lines • 4.71 kB
JavaScript
import { DelayError, DelayErrorCode } from '../types/index.js';
export function nextFrame() {
if (typeof requestAnimationFrame === 'undefined') {
throw new DelayError('requestAnimationFrame is not available in this environment', DelayErrorCode.UNSUPPORTED_ENVIRONMENT, { feature: 'requestAnimationFrame' });
}
return new Promise((resolve) => {
requestAnimationFrame(resolve);
});
}
export function nextFrames(count) {
if (count <= 0) {
throw new DelayError('Frame count must be positive', DelayErrorCode.INVALID_OPTIONS, { count });
}
if (count === 1) {
return nextFrame();
}
return new Promise((resolve) => {
let remaining = count;
const tick = (timestamp) => {
remaining--;
if (remaining <= 0) {
resolve(timestamp);
}
else {
requestAnimationFrame(tick);
}
};
requestAnimationFrame(tick);
});
}
export function idle(options = {}) {
if (typeof requestIdleCallback === 'undefined') {
// Fallback for environments without requestIdleCallback
return new Promise((resolve) => {
setTimeout(() => {
resolve({
didTimeout: false,
timeRemaining() {
return 50; // Assume 50ms remaining
},
});
}, 0);
});
}
return new Promise((resolve, reject) => {
const id = requestIdleCallback(resolve, options);
// Optional timeout handling
if (options.timeout) {
setTimeout(() => {
if (typeof cancelIdleCallback !== 'undefined') {
cancelIdleCallback(id);
}
reject(new DelayError(`Idle callback timed out after ${options.timeout}ms`, DelayErrorCode.TIMEOUT, { timeout: options.timeout }));
}, options.timeout);
}
});
}
export function waitForDOMReady() {
if (typeof document === 'undefined') {
throw new DelayError('DOM is not available in this environment', DelayErrorCode.UNSUPPORTED_ENVIRONMENT, { feature: 'document' });
}
if (document.readyState === 'complete' || document.readyState === 'interactive') {
return Promise.resolve();
}
return new Promise((resolve) => {
const handler = () => {
document.removeEventListener('DOMContentLoaded', handler);
resolve();
};
document.addEventListener('DOMContentLoaded', handler);
});
}
export function waitForWindowLoad() {
if (typeof window === 'undefined') {
throw new DelayError('Window is not available in this environment', DelayErrorCode.UNSUPPORTED_ENVIRONMENT, { feature: 'window' });
}
if (document.readyState === 'complete') {
return Promise.resolve();
}
return new Promise((resolve) => {
const handler = () => {
window.removeEventListener('load', handler);
resolve();
};
window.addEventListener('load', handler);
});
}
export function waitForVisibilityChange(visible) {
if (typeof document === 'undefined') {
throw new DelayError('Document is not available in this environment', DelayErrorCode.UNSUPPORTED_ENVIRONMENT, { feature: 'document' });
}
// Check current state
const isCurrentlyVisible = !document.hidden;
if (isCurrentlyVisible === visible) {
return Promise.resolve();
}
return new Promise((resolve) => {
const handler = () => {
const isVisible = !document.hidden;
if (isVisible === visible) {
document.removeEventListener('visibilitychange', handler);
resolve();
}
};
document.addEventListener('visibilitychange', handler);
});
}
export function createFrameBasedDelay(frames) {
return nextFrames(frames);
}
export function createIdleDelay(maxWait = 5000) {
return idle({ timeout: maxWait });
}
export function isRequestAnimationFrameAvailable() {
return typeof requestAnimationFrame !== 'undefined';
}
export function isRequestIdleCallbackAvailable() {
return typeof requestIdleCallback !== 'undefined';
}
export function getEnvironmentCapabilities() {
return {
hasRequestAnimationFrame: isRequestAnimationFrameAvailable(),
hasRequestIdleCallback: isRequestIdleCallbackAvailable(),
hasPerformanceNow: typeof performance !== 'undefined' && !!performance.now,
hasDocument: typeof document !== 'undefined',
hasWindow: typeof window !== 'undefined',
};
}
//# sourceMappingURL=browser.js.map