forked from rocicorp/mono
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsleep.ts
More file actions
72 lines (60 loc) · 1.89 KB
/
sleep.ts
File metadata and controls
72 lines (60 loc) · 1.89 KB
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
import {resolver} from '@rocicorp/resolver';
import {AbortError} from './abort-error.ts';
const promiseVoid = Promise.resolve();
const promiseNever = new Promise<void>(() => undefined);
/**
* Creates a promise that resolves after `ms` milliseconds. Note that if you
* pass in `0` no `setTimeout` is used and the promise resolves immediately. In
* other words no macro task is used in that case.
*
* Pass in an AbortSignal to clear the timeout.
*/
export function sleep(ms: number, signal?: AbortSignal): Promise<void> {
const newAbortError = () => new AbortError('Aborted');
if (signal?.aborted) {
return Promise.reject(newAbortError());
}
if (ms === 0) {
return promiseVoid;
}
return new Promise((resolve, reject) => {
let handleAbort: () => void;
if (signal) {
handleAbort = () => {
clearTimeout(id);
reject(newAbortError());
};
signal.addEventListener('abort', handleAbort, {once: true});
}
const id = setTimeout(() => {
resolve();
signal?.removeEventListener('abort', handleAbort);
}, ms);
});
}
/**
* Returns a pair of promises. The first promise resolves after `ms` milliseconds
* unless the AbortSignal is aborted. The second promise resolves when the AbortSignal
* is aborted.
*/
export function sleepWithAbort(
ms: number,
signal: AbortSignal,
): [ok: Promise<void>, aborted: Promise<void>] {
if (ms === 0) {
return [promiseVoid, promiseNever];
}
const {promise: abortedPromise, resolve: abortedResolve} = resolver<void>();
const sleepPromise = new Promise<void>(resolve => {
const handleAbort = () => {
clearTimeout(id);
abortedResolve();
};
const id = setTimeout(() => {
resolve();
signal.removeEventListener('abort', handleAbort);
}, ms);
signal.addEventListener('abort', handleAbort, {once: true});
});
return [sleepPromise, abortedPromise];
}