-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.ts
141 lines (129 loc) · 4.44 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import {packageTracer} from '@alwatr/package-tracer';
import {parseDuration, type DurationString} from '@alwatr/parse-duration';
packageTracer.add(__package_name__, __package_version__);
import {requestAnimationFrame, requestIdleCallback} from './polyfill.js';
import type {HasAddEventListener} from '@alwatr/type-helper';
/**
* A utility module to help manage asynchronous operations and waiting for events or timeouts.
*/
export const delay = {
/**
* Delays execution for a specified duration (in milliseconds).
*
* @param duration - The duration to wait (in milliseconds). Use `0` to yield control to the event loop.
* @returns A Promise that resolves after the specified duration.
*
* @example
* ```typescript
* await delay.by('1m'); // Wait for 1 minute
* ```
*/
by: (duration: DurationString): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, parseDuration(duration))),
/**
* Delays execution until the next animation frame.
*
* @returns A Promise that resolves with the current timestamp when the next animation frame is fired.
*
* @example
* ```typescript
* const timestamp = await delay.untilNextAnimationFrame();
* ```
*/
untilNextAnimationFrame: (): Promise<DOMHighResTimeStamp> =>
new Promise((resolve) => requestAnimationFrame(resolve)),
/**
* Delays execution until the browser's idle period or the specified timeout.
*
* @param timeout - Optional timeout (in milliseconds) for the idle callback.
* @returns A Promise that resolves with the IdleDeadline object when the browser is idle or the timeout is reached.
*
* @example
* ```typescript
* const deadline = await delay.untilIdle();
* ```
*/
untilIdle: (timeout?: DurationString): Promise<IdleDeadline> =>
new Promise((resolve) => requestIdleCallback(resolve, timeout === undefined ? undefined : {
timeout: parseDuration(timeout)
})),
/**
* Delays execution until a specific DOM event occurs on an HTMLElement.
*
* @param element - The HTMLElement to listen for the event on.
* @param eventName - The name of the DOM event to wait for.
* @template T The event map type.
* @returns A Promise that resolves with the event object when the specified event occurs.
*
* @example
* ```typescript
* const clickEvent = await delay.untilDomEvent(document.body, 'click');
* ```
*/
untilDomEvent: <T extends keyof HTMLElementEventMap>(
element: HTMLElement,
eventName: T
): Promise<HTMLElementEventMap[T]> =>
new Promise((resolve) =>
element.addEventListener(eventName, resolve, { once: true, passive: true })
),
/**
* Delays execution until a specific event occurs on an object with an `addEventListener` method.
*
* @param target - The target object to listen for the event on.
* @param eventName - The name of the event to wait for.
* @returns A Promise that resolves with the event object when the specified event occurs.
*
* @example
* ```typescript
* const server = http.createServer();
* const requestEvent = await delay.untilEvent(server, 'request');
* ```
*/
untilEvent: (target: HasAddEventListener, eventName: string): Promise<Event> =>
new Promise((resolve) =>
target.addEventListener(eventName, resolve, { once: true, passive: true })
),
/**
* Yields control to the event loop immediately.
*
* Uses `setImmediate` if available, falls back to `queueMicrotask`, and then to `setTimeout(0)`.
*
* @returns A Promise that resolves immediately after yielding control to the event loop.
*
* @example
* ```typescript
* await delay.immediate();
* ```
*/
immediate: (): Promise<void> => {
if (typeof setImmediate !== 'function') {
if (typeof queueMicrotask === 'function') {
return delay.nextMicrotask();
}
// else
return delay.by(0);
}
return new Promise((resolve) => setImmediate(resolve));
},
/**
* Delays execution until the next microtask queue is empty
*
* @returns A Promise that resolves when the next microtask queue is empty.
*
* @example
* ```typescript
* await delay.nextMicrotask();
* ```
*/
nextMicrotask: (): Promise<void> => {
if (typeof queueMicrotask !== 'function') {
if (typeof setImmediate === 'function') {
return delay.immediate();
}
// else
return delay.by(0);
}
return new Promise((resolve) => queueMicrotask(resolve));
},
} as const;