-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmanager.ts
86 lines (75 loc) · 2.67 KB
/
manager.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
import type { getAllImages, getPdfDoc, processPDF } from './pdf';
export interface WorkerMethods {
getAllImages: typeof getAllImages;
getPdfDoc: typeof getPdfDoc;
processPDF: typeof processPDF;
close: typeof Worker.prototype.terminate;
}
export type WorkerMethodParams<T extends keyof WorkerMethods> = Parameters<WorkerMethods[T]>;
export type WorkerMethodResult<T extends keyof WorkerMethods> = ReturnType<WorkerMethods[T]>;
type UnwrapPromise<T> = Promise<Awaited<T>>; // 防止双重Promise
type QuerySlave<K extends keyof WorkerMethods> = (
method: K,
...params: WorkerMethodParams<K>
) => UnwrapPromise<WorkerMethodResult<K>>;
type QueryMaster = (method: 'eval', cmd: string) => Promise<any>;
type WorkerMode = Worker | DedicatedWorkerGlobalScope;
export abstract class WorkerManagerBase<T extends WorkerMode> {
private readonly queue = new TaskQueue();
constructor(protected readonly that: T) {
that.onmessage = event => {
if (event.data?.response) this.onResponse(event.data.response);
else if (event.data?.request) this.onRequest(event.data.request);
else this.onDefault(event.data);
};
}
protected abstract onRequest(request: WorkerRequest<T>): void;
protected onDefault(data: any) {
throw new Error('Unknown message: ' + JSON.stringify(data));
}
private onResponse(response: WorkerResponse) {
const { resolve } = this.queue.pop(response.id);
resolve(response.result);
}
query: T extends Worker ? QuerySlave<keyof WorkerMethods> : QueryMaster = (
method: any,
...params: any[]
) => {
return new Promise<any>((resolve, reject) => {
const id = this.queue.push({ resolve, reject }),
request: WorkerRequest<T> = { id, method, params };
this.that.postMessage({ request });
});
};
}
export interface WorkerRequest<T extends WorkerMode, K extends keyof WorkerMethods = any> {
id: number;
method: T extends Worker ? K : 'eval';
params?: T extends Worker ? WorkerMethodParams<K> : any[];
}
export interface WorkerResponse {
id: number;
result: Awaited<WorkerMethodResult<keyof WorkerMethods>>;
}
export interface WorkerStream {
[key: string]: any;
method: string;
payload: object;
}
interface Task {
resolve: (value: any) => void;
reject: (reason?: any) => void;
}
class TaskQueue {
private readonly data: { [id: number]: Task } = {};
private head = 0;
push(task: Task) {
this.data[this.head] = task;
return this.head++;
}
pop(id: number) {
const task = this.data[id];
delete this.data[id];
return task;
}
}