id-scanner-lib
Version:
Browser-based ID card, QR code, and face recognition scanner with liveness detection
130 lines (121 loc) • 3.19 kB
text/typescript
/**
* @file WorkerBridge - Web Worker 并行处理框架
* @description 提供基于 Promise 的 Worker 通信接口,支持超时和错误处理
* @module core/utils/worker
*/
/**
* Worker 消息格式
*/
export type WorkerMessage<T = any> = {
type: string;
payload: T;
id: string;
};
/**
* Worker 响应格式
*/
export type WorkerResponse<T = any> = {
type: string;
payload: T;
error?: string;
id: string;
};
/**
* WorkerBridge - 基于 Promise 的 Worker 通信桥接器
*
* 提供简洁的 Worker 消息发送接口,自动处理请求-响应匹配、超时和错误
*
* @example
* ```typescript
* const bridge = new WorkerBridge('/workers/face-detect.worker.ts');
* await bridge.load();
* const result = await bridge.post('detect', { imageData });
* bridge.terminate();
* ```
*/
export class WorkerBridge<TReq = any, TRes = any> {
private _worker: Worker | null = null;
private _pending: Map<string, { resolve: Function; reject: Function }> = new Map();
private _url: string;
/**
* 创建 WorkerBridge
* @param workerUrl Worker 文件 URL
*/
constructor(workerUrl: string) {
this._url = workerUrl;
}
/**
* 加载 Worker
*/
async load(): Promise<void> {
this._worker = new Worker(this._url);
this._worker.onmessage = (e: MessageEvent<WorkerResponse<TRes>>) => {
const { id, payload, error } = e.data;
const handlers = this._pending.get(id);
if (handlers) {
if (error) {
handlers.reject(new Error(error));
} else {
handlers.resolve(payload);
}
this._pending.delete(id);
}
};
this._worker.onerror = (e) => {
// 将 Worker 错误广播给所有 pending 的 Promise
for (const [id, handlers] of this._pending) {
handlers.reject(new Error(`Worker error: ${e.message}`));
this._pending.delete(id);
}
};
}
/**
* 发送消息到 Worker 并等待响应
*
* @param type 消息类型
* @param payload 消息载荷
* @returns 响应 Promise
* @throws 如果 Worker 未加载则抛出错误
*/
async post(type: string, payload: TReq): Promise<TRes> {
if (!this._worker) {
throw new Error('Worker not loaded');
}
const id = crypto.randomUUID();
return new Promise((resolve, reject) => {
this._pending.set(id, { resolve, reject });
this._worker!.postMessage({ type, payload, id } as WorkerMessage<TReq>);
// 超时 30s
setTimeout(() => {
if (this._pending.has(id)) {
this._pending.delete(id);
reject(new Error('Worker timeout'));
}
}, 30000);
});
}
/**
* 终止 Worker
*/
terminate(): void {
this._worker?.terminate();
this._worker = null;
// 拒绝所有 pending 的 Promise
for (const [, handlers] of this._pending) {
handlers.reject(new Error('Worker terminated'));
}
this._pending.clear();
}
/**
* 检查 Worker 是否已加载
*/
get isLoaded(): boolean {
return this._worker !== null;
}
/**
* 获取当前 pending 请求数
*/
get pendingCount(): number {
return this._pending.size;
}
}