This repository has been archived by the owner on Feb 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
index.ts
98 lines (77 loc) · 2.58 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
93
94
95
96
97
98
const _outstandingPromiseInstanceMap = new WeakMap<Object, Set<Promise<any>>>();
const _outstandingPromiseMap = new Map<Promise<any>, boolean>();
export function tracked<T extends Object>(
target: T,
key: string | Symbol,
descriptor: PropertyDescriptor
) {
if (typeof descriptor.value !== "function" || !target.constructor) {
throw new Error("The 'tracked' decorator can only be applied to methods.");
}
const impl = descriptor.value;
// wrapper function that keeps a list of outstanding promises for each
// instance of DashboardMessageBusClient
function newImpl(...args: any[]) {
const returnValue = impl.apply(this, args);
// only track async functions
if (returnValue?.then && typeof returnValue.then === "function") {
const trackedTask = returnValue.finally(() => {
_cleanUpTrackedTask(this, trackedTask);
});
_trackTask(this, trackedTask);
return trackedTask;
}
return returnValue;
}
return {
...descriptor,
value: newImpl
};
}
export interface WaitForOutstandingPromiseOptions<T> {
catchHandler?: (err?: any) => void;
target?: T;
}
export async function waitForOutstandingPromises<T extends Object>(
options?: WaitForOutstandingPromiseOptions<T>
) {
const { target } = options || {};
let { catchHandler } = options || {};
const iterable =
(target
? _outstandingPromiseInstanceMap.get(target)?.values()
: _outstandingPromiseMap.keys()) || [];
catchHandler = catchHandler || (() => {});
await Promise.all(Array.from(iterable, p => p.catch(catchHandler)));
}
function _trackTask<T extends Object>(target: T, trackedTask: Promise<any>) {
if (!_outstandingPromiseInstanceMap.has(target)) {
_outstandingPromiseInstanceMap.set(target, new Set<Promise<void>>());
}
_outstandingPromiseInstanceMap.get(target)!.add(trackedTask);
_outstandingPromiseMap.set(trackedTask, true);
}
function _cleanUpTrackedTask<T extends Object>(
target: T,
trackedTask: Promise<any>
) {
_outstandingPromiseMap.delete(trackedTask);
const promises = _outstandingPromiseInstanceMap.get(target);
promises?.delete(trackedTask);
if (promises?.size === 0) {
_outstandingPromiseInstanceMap.delete(target);
}
}
export interface GetOutstandingPromiseOptions<T> {
target?: T;
}
export function getOutstandingPromises<T extends Object>(
options: GetOutstandingPromiseOptions<T>
): Promise<any>[] {
const { target } = options;
const iterable =
(target
? _outstandingPromiseInstanceMap.get(target)?.values()
: _outstandingPromiseMap.keys()) || [];
return Array.from(iterable);
}