-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPromiseStore.ts
75 lines (61 loc) · 1.74 KB
/
PromiseStore.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
import {Logger} from '../logger/index.js';
import {PartialRecord} from '../types.js';
function generateId() {
return `${Date.now()}-${Math.random()}`;
}
export class PromiseStore {
protected promiseRecord: PartialRecord<string, Promise<unknown>> = {};
protected isClosed = false;
constructor(protected logger: Logger = console) {}
/** Add a promise, but handle it's failure if it fails and do nothing. */
forget(promise: unknown) {
const id: string = generateId();
this.replace(promise, id, /** forget */ true);
return this;
}
/** Returns a promise resolved when all the promises at the time of calling
* are resolved. This does not include promises stored after this call. */
async flush() {
await Promise.allSettled(Object.values(this.promiseRecord));
}
/** Prevents addition of new promises. */
close() {
this.isClosed = true;
return this;
}
isStoreClosed() {
return this.isClosed;
}
callAndForget(fn: () => void | Promise<void>) {
try {
this.forget(fn());
} catch (error) {
this.logger.error(error);
}
}
protected assertNotClosed() {
if (this.isClosed) {
throw new Error('PromiseStore is closed');
}
}
protected replace(promise: unknown, id: string, forget = false) {
this.assertNotClosed();
if (!(promise instanceof Promise)) {
return;
}
if (forget) {
promise = this.awaitForgetPromise(promise);
}
this.promiseRecord[id] = promise as Promise<unknown>;
(promise as Promise<unknown>).finally(() => {
delete this.promiseRecord[id];
});
}
protected async awaitForgetPromise(p: Promise<unknown>): Promise<void> {
try {
await p;
} catch (error) {
this.logger.error(error);
}
}
}