/
one-more-time.ts
85 lines (74 loc) · 2.21 KB
/
one-more-time.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
/**
* Used to configure the OneMoreTime instance
*/
export interface OneMoreTimeOptions {
/**
* Represents the value in ms that will be used to delay the next call
* Remember that this value is applied after the action is executed, it does
* not count the time the action takes to execute
* @type {number}
*/
delay?: number
/**
* When some error happens, this value in ms will be delayed to the next call
* @type {number}
*/
errorDelay?: number
/**
* If true, the action will be executed immediately after the object is created
* @type {boolean}
*/
autostart?: boolean
}
/**
* After multiple years and attempts
* This is a RAII class that takes advantage of the new disposable feature
* to create a promise that repeats itself until it's disposed
*/
export default class OneMoreTime {
private isDisposed = false
constructor(
private readonly action: () => Promise<void>,
private readonly options: OneMoreTimeOptions = {}
) {
// One more time
if (options.autostart ?? true) {
// eslint-disable-next-line no-return-await
(async () => await this.start())()
}
}
async start(): Promise<void> {
// Come on, alright
if (this.isDisposed) return
try {
// One more time, we're gonna celebrate
await this.action()
} catch (error) {
console.error('Error in self-calling promise:', error)
// Oh yeah, alright, don't stop the dancing
// eslint-disable-next-line no-promise-executor-return
await new Promise((resolve) => setTimeout(resolve, this.options.errorDelay))
}
setTimeout(() => this.start(), this.options.delay)
}
// Celebrate and dance so free
[Symbol.dispose](): void {
this.stop()
}
// Stop timer
stop(): void {
this.isDisposed = true
}
}
/** Example
async function logTimestamp() {
console.log('Current timestamp:', new Date())
await new Promise(resolve => setTimeout(resolve, 1000)) // Simulate some async work
}
(async () => {
console.log("started")
using task = new OneMoreTime(logTimestamp)
await new Promise(resolve => setTimeout(resolve, 5000)) // Simulate some async work
console.log("done")
})()
*/