diff options
Diffstat (limited to 'subprojects/frontend/src/utils/ConditionVariable.ts')
-rw-r--r-- | subprojects/frontend/src/utils/ConditionVariable.ts | 64 |
1 files changed, 0 insertions, 64 deletions
diff --git a/subprojects/frontend/src/utils/ConditionVariable.ts b/subprojects/frontend/src/utils/ConditionVariable.ts deleted file mode 100644 index 1d3431f7..00000000 --- a/subprojects/frontend/src/utils/ConditionVariable.ts +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | import PendingTask from './PendingTask'; | ||
2 | import getLogger from './getLogger'; | ||
3 | |||
4 | const log = getLogger('utils.ConditionVariable'); | ||
5 | |||
6 | export type Condition = () => boolean; | ||
7 | |||
8 | export default class ConditionVariable { | ||
9 | private readonly condition: Condition; | ||
10 | |||
11 | private readonly defaultTimeout: number; | ||
12 | |||
13 | private listeners: PendingTask<void>[] = []; | ||
14 | |||
15 | constructor(condition: Condition, defaultTimeout = 0) { | ||
16 | this.condition = condition; | ||
17 | this.defaultTimeout = defaultTimeout; | ||
18 | } | ||
19 | |||
20 | async waitFor(timeoutMs?: number | undefined): Promise<void> { | ||
21 | if (this.condition()) { | ||
22 | return; | ||
23 | } | ||
24 | const timeoutOrDefault = timeoutMs ?? this.defaultTimeout; | ||
25 | let nowMs = Date.now(); | ||
26 | const endMs = nowMs + timeoutOrDefault; | ||
27 | while (!this.condition() && nowMs < endMs) { | ||
28 | const remainingMs = endMs - nowMs; | ||
29 | const promise = new Promise<void>((resolve, reject) => { | ||
30 | if (this.condition()) { | ||
31 | resolve(); | ||
32 | return; | ||
33 | } | ||
34 | const task = new PendingTask(resolve, reject, remainingMs); | ||
35 | this.listeners.push(task); | ||
36 | }); | ||
37 | // We must keep waiting until the update has completed, | ||
38 | // so the tasks can't be started in parallel. | ||
39 | // eslint-disable-next-line no-await-in-loop | ||
40 | await promise; | ||
41 | nowMs = Date.now(); | ||
42 | } | ||
43 | if (!this.condition()) { | ||
44 | log.error('Condition still does not hold after', timeoutOrDefault, 'ms'); | ||
45 | throw new Error('Failed to wait for condition'); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | notifyAll(): void { | ||
50 | this.clearListenersWith((listener) => listener.resolve()); | ||
51 | } | ||
52 | |||
53 | rejectAll(error: unknown): void { | ||
54 | this.clearListenersWith((listener) => listener.reject(error)); | ||
55 | } | ||
56 | |||
57 | private clearListenersWith(callback: (listener: PendingTask<void>) => void) { | ||
58 | // Copy `listeners` so that we don't get into a race condition | ||
59 | // if one of the listeners adds another listener. | ||
60 | const { listeners } = this; | ||
61 | this.listeners = []; | ||
62 | listeners.forEach(callback); | ||
63 | } | ||
64 | } | ||