-
Notifications
You must be signed in to change notification settings - Fork 3
/
looper.node.ts
76 lines (60 loc) · 1.84 KB
/
looper.node.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
// looper.node
// ===========
import { Worker } from 'worker_threads'
import type { Looper } from '../looper'
type Listener = () => void
type WrappedListener = (message: string) => void
export class NodeLooper implements Looper {
private worker: Worker | undefined
private readonly listenerMap = new Map<string, Map<Listener, WrappedListener>>()
post (message: string): void {
if (this.worker === undefined) {
return
}
this.worker.postMessage(message)
}
on (message: string, listener: () => void): void {
if (this.worker === undefined) {
this.worker = this.createWorker()
}
this.worker.on('message', this.wrapListener(message, listener))
}
off (message: string, listener: () => void): void {
if (this.worker === undefined) {
return
}
this.worker.off('message', this.wrapListener(message, listener))
if (!this.workerHasListeners()) {
this.destroyWorker()
}
}
private createWorker (): Worker {
return new Worker(new URL('./worker.ts', import.meta.url))
}
private destroyWorker (): void {
if (this.worker !== undefined) {
this.worker.terminate()
this.worker = undefined
}
}
private workerHasListeners (): boolean {
return this.worker !== undefined && this.worker.listenerCount('message') > 0
}
private wrapListener (message: string, listener: () => void): WrappedListener {
let secondary = this.listenerMap.get(message)
if (secondary === undefined) {
secondary = new Map<Listener, WrappedListener>()
this.listenerMap.set(message, secondary)
}
let wrapped = secondary.get(listener)
if (wrapped === undefined) {
wrapped = (postedMessage: string): void => {
if (postedMessage === message) {
listener()
}
}
secondary.set(listener, wrapped)
}
return wrapped
}
}