-
Notifications
You must be signed in to change notification settings - Fork 0
/
request-timeout.ts
110 lines (105 loc) · 3.16 KB
/
request-timeout.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
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { AnyFunction } from '@oakfinch/ts-extra'
import { assign } from '../../object/assign'
import { getPromise } from '../../promise/get-promise'
import { isObject } from '../../type-guards/is-object'
import { getTimeout } from './helpers'
import { IDLE } from './constants'
import type { RequestCallback, TimeoutType, Idle, AnimationFrame } from './types'
/**
* A combined interface for setTimeout, requestIdleCallback, and
* requestAnimationFrame
*
* @param fn callback function
* @param type callback type. `idle`, `animationFrame`, or a number of
* milliseconds
* @returns returns a promise-like function that, when called, will cancel the
* timeout. When `await`-ed, it will resolve with the return value of
* the callback once it is called, or will reject
*
* @example
* ```
* import { timeout } from '@oakfinch/ts-utils'
*
* timeout(() => { console.log('this will be called when idle') })
*
* await timeout(() => { console.log('you can await the result as well') })
*
* timeout(
* () => { console.log('this calls requestIdleCallback') },
* 'idle'
* )
*
* timeout(
* () => { console.log('this calls requestAnimationFrame') },
* 'animationFrame'
* )
*
* timeout(
* () => { console.log('this calls setTimeout') },
* 100
* )
*
* const { cancel } = timeout(
* () => { console.log('this will be canceled!') },
* 100
* )
* cancel()
*
* const promise = timeout(
* () => {
* console.log('this will be canceled and the promise will reject')
* },
* 100
* )
* timeout(() => { promise.cancel({ error: true }) })
* await promise
*
* ```
*/
export function requestTimeout(
fn: RequestCallback<Idle>
): Promise<void> & { cancel: (options?: { error?: any }) => true }
export function requestTimeout(
fn: RequestCallback<Idle>,
type: Idle
): Promise<void> & { cancel: (options?: { error?: any }) => true }
export function requestTimeout(
fn: RequestCallback<Idle>,
options: IdleRequestOptions
): Promise<void> & { cancel: (options?: { error?: any }) => true }
export function requestTimeout(
fn: RequestCallback<AnimationFrame>,
type: AnimationFrame
): Promise<void> & { cancel: (options?: { error?: any }) => true }
export function requestTimeout(
fn: RequestCallback<number>,
type: number
): Promise<void> & { cancel: (options?: { error?: any }) => true }
export function requestTimeout(
fn: RequestCallback<number | TimeoutType>,
typeOrOptions: number | TimeoutType | IdleRequestOptions = IDLE
): Promise<void> & { cancel: (options?: { error?: any }) => true } {
const { resolve, reject, promise } = getPromise()
const [type, options] = isObject(typeOrOptions)
? ([IDLE, typeOrOptions] as const)
: ([typeOrOptions, undefined] as const)
const [request, clear] = getTimeout(type, options)
const id = request((...args) => {
try {
;(fn as AnyFunction)(...args)
resolve()
} catch (error) {
reject(error)
}
})
const cancel = ({ error = false } = {}): true => {
clear(id)
if (error) {
reject(error)
}
return true
}
return assign(promise, { cancel })
}
export default requestTimeout