feat: get web worker mechanism working (pass file around)

This commit is contained in:
鲁树人
2023-05-08 17:36:10 +01:00
parent 29b169cce6
commit 911ee2a2fa
7 changed files with 150 additions and 6 deletions

View File

@@ -0,0 +1,40 @@
export abstract class ConcurrentQueue<T> {
protected items: [T, (result: any) => void, (error: Error) => void][] = [];
protected currentlyWorking = 0;
constructor(protected maxQueue = 5) {}
abstract handler(item: T): Promise<void>;
public async add<R = never>(item: T): Promise<R> {
return new Promise((resolve, reject) => {
this.items.push([item, resolve, reject]);
this.runWorkerIfFree();
});
}
private runWorkerIfFree() {
if (this.currentlyWorking < this.maxQueue) {
this.currentlyWorking++;
this.processQueue()
.catch((e) => {
console.error('process queue with error', e);
})
.finally(() => {
this.currentlyWorking--;
});
}
}
private async processQueue() {
while (true) {
const item = this.items.pop();
if (item === undefined) {
break;
}
const [payload, resolve, reject] = item;
await this.handler(payload).then(resolve).catch(reject);
}
}
}

View File

@@ -0,0 +1,62 @@
import { nanoid } from 'nanoid';
export class WorkerClientBus {
private idPromiseMap = new Map<string, [(data: any) => void, (error: Error) => void]>();
constructor(private worker: Worker) {
worker.addEventListener('message', (e) => {
const { id, result, error } = e.data;
const actionPromise = this.idPromiseMap.get(id);
if (!actionPromise) {
console.error('cound not fetch worker promise for action: %s', id);
return;
}
this.idPromiseMap.delete(id);
const [resolve, reject] = actionPromise;
if (error) {
reject(error);
} else {
resolve(result);
}
});
}
async request<R = any, P = any>(actionName: string, payload: P): Promise<R> {
return new Promise((resolve, reject) => {
const id = nanoid();
this.idPromiseMap.set(id, [resolve, reject]);
this.worker.postMessage({
id,
action: actionName,
payload,
});
});
}
}
export class WorkerServerBus {
private handlers = new Map<string, (payload: any) => Promise<any>>();
addEventHandler<R = any, P = any>(actionName: string, handler: (payload: P) => Promise<R>) {
this.handlers.set(actionName, handler);
}
onmessage = async (e: MessageEvent<any>) => {
const { id, action, payload } = e.data;
const handler = this.handlers.get(action);
if (!handler) {
postMessage({ id, result: null, error: new Error('Handler missing for action ' + action) });
return;
}
let result = undefined;
let error = undefined;
try {
result = await handler(payload);
} catch (e: unknown) {
error = e;
}
postMessage({ id, result, error });
};
}