(
ms: number,
signal?: AbortSignal,
opts?: { throwOnAbort?: boolean; abortError?: () => Error; unref?: boolean },
)
| 12 | * error class (e.g. `APIUserAbortError`). |
| 13 | */ |
| 14 | export function sleep( |
| 15 | ms: number, |
| 16 | signal?: AbortSignal, |
| 17 | opts?: { throwOnAbort?: boolean; abortError?: () => Error; unref?: boolean }, |
| 18 | ): Promise<void> { |
| 19 | return new Promise((resolve, reject) => { |
| 20 | // Check aborted state BEFORE setting up the timer. If we defined |
| 21 | // onAbort first and called it synchronously here, it would reference |
| 22 | // `timer` while still in the Temporal Dead Zone. |
| 23 | if (signal?.aborted) { |
| 24 | if (opts?.throwOnAbort || opts?.abortError) { |
| 25 | void reject(opts.abortError?.() ?? new Error('aborted')) |
| 26 | } else { |
| 27 | void resolve() |
| 28 | } |
| 29 | return |
| 30 | } |
| 31 | const timer = setTimeout( |
| 32 | (signal, onAbort, resolve) => { |
| 33 | signal?.removeEventListener('abort', onAbort) |
| 34 | void resolve() |
| 35 | }, |
| 36 | ms, |
| 37 | signal, |
| 38 | onAbort, |
| 39 | resolve, |
| 40 | ) |
| 41 | function onAbort(): void { |
| 42 | clearTimeout(timer) |
| 43 | if (opts?.throwOnAbort || opts?.abortError) { |
| 44 | void reject(opts.abortError?.() ?? new Error('aborted')) |
| 45 | } else { |
| 46 | void resolve() |
| 47 | } |
| 48 | } |
| 49 | signal?.addEventListener('abort', onAbort, { once: true }) |
| 50 | if (opts?.unref) { |
| 51 | timer.unref() |
| 52 | } |
| 53 | }) |
| 54 | } |
| 55 | |
| 56 | function rejectWithTimeout(reject: (e: Error) => void, message: string): void { |
| 57 | reject(new Error(message)) |
no test coverage detected