-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathindex.ts
92 lines (85 loc) · 2.61 KB
/
index.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
import { PersistedClient, Persister } from '../persistQueryClient'
interface AsyncStorage {
getItem: (key: string) => Promise<string | null>
setItem: (key: string, value: string) => Promise<void>
removeItem: (key: string) => Promise<void>
}
interface CreateAsyncStoragePersisterOptions {
/** The storage client used for setting an retrieving items from cache */
storage: AsyncStorage
/** The key to use when storing the cache */
key?: string
/** To avoid spamming,
* pass a time in ms to throttle saving the cache to disk */
throttleTime?: number
/**
* How to serialize the data to storage.
* @default `JSON.stringify`
*/
serialize?: (client: PersistedClient) => string
/**
* How to deserialize the data from storage.
* @default `JSON.parse`
*/
deserialize?: (cachedString: string) => PersistedClient
}
export const createAsyncStoragePersister = ({
storage,
key = `REACT_QUERY_OFFLINE_CACHE`,
throttleTime = 1000,
serialize = JSON.stringify,
deserialize = JSON.parse,
}: CreateAsyncStoragePersisterOptions): Persister => {
return {
persistClient: asyncThrottle(
persistedClient => storage.setItem(key, serialize(persistedClient)),
{ interval: throttleTime }
),
restoreClient: async () => {
const cacheString = await storage.getItem(key)
if (!cacheString) {
return
}
return deserialize(cacheString) as PersistedClient
},
removeClient: () => storage.removeItem(key),
}
}
function asyncThrottle<Args extends readonly unknown[], Result>(
func: (...args: Args) => Promise<Result>,
{ interval = 1000, limit = 1 }: { interval?: number; limit?: number } = {}
) {
if (typeof func !== 'function') throw new Error('argument is not function.')
const running = { current: false }
let lastTime = 0
let timeout: ReturnType<typeof setTimeout>
const queue: Array<Args> = []
return (...args: Args) =>
(async () => {
if (running.current) {
lastTime = Date.now()
if (queue.length > limit) {
queue.shift()
}
queue.push(args)
clearTimeout(timeout)
}
if (Date.now() - lastTime > interval) {
running.current = true
await func(...args)
lastTime = Date.now()
running.current = false
} else {
if (queue.length > 0) {
const lastArgs = queue[queue.length - 1]!
timeout = setTimeout(async () => {
if (!running.current) {
running.current = true
await func(...lastArgs)
running.current = false
}
}, interval)
}
}
})()
}