UNPKG

parallel-file-uploader

Version:

高性能并行文件上传工具,支持大文件分片上传、断点续传、Web Worker多线程处理

221 lines (217 loc) 6.72 kB
/** * Worker管理器 * 管理Web Worker线程池,处理数据分片处理 */ export class WorkerManager { constructor() { this.workerPool = []; this.workerBusy = new Map(); this.messageHandlers = new Map(); this.initializeWorkers(); } /** * 创建Worker实例 */ createWorker() { // 在浏览器环境中,创建内联Worker if (typeof window !== 'undefined' && typeof Blob !== 'undefined') { try { // 创建包含worker代码的内联Worker const workerCode = ` // Web Worker实现文件分片处理 // 专门负责数据处理,不进行网络请求 // 适配Worker环境 const ctx = self; ctx.onmessage = async function (e) { const message = e.data; // 处理所有包含文件数据的消息 if (message.fileId && message.chunkInfo) { const { fileId, chunkInfo } = message; try { // 将处理后的数据发送回主线程 ctx.postMessage({ type: 'response', fileId, chunkInfo, processed: true, result: { file: chunkInfo.file, // 返回处理后的Blob partNumber: chunkInfo.partNumber, partSize: chunkInfo.partSize, }, }); } catch (error) { // 发送错误消息 ctx.postMessage({ type: 'error', fileId, chunkInfo, error: error instanceof Error ? error.message : String(error), }); } } }; // 通知主线程Worker已经准备就绪 ctx.postMessage({ type: 'ready' }); `; const blob = new Blob([workerCode], { type: 'application/javascript' }); const workerUrl = URL.createObjectURL(blob); const worker = new Worker(workerUrl); // 清理Blob URL(可选,但是好的实践) worker.addEventListener('message', () => { URL.revokeObjectURL(workerUrl); }, { once: true }); return worker; } catch (e) { console.warn('Failed to create inline worker:', e); } } // 回退方案:尝试加载外部worker文件 try { // 在开发环境中,尝试加载编译后的文件 return new Worker('./lib/worker.js'); } catch (e) { try { // 生产环境的另一个路径 return new Worker('/lib/worker.js'); } catch (e2) { // 最终回退 return new Worker('./worker.js'); } } } /** * 初始化Worker池 */ initializeWorkers() { if (typeof Worker === 'undefined') { console.warn('Web Workers not supported in this environment'); return; } // 在测试环境中跳过Worker初始化 if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'test') { console.log('Skipping worker initialization in test environment'); return; } const workerCount = Math.min(navigator.hardwareConcurrency || 4, 8); for (let i = 0; i < workerCount; i++) { try { const worker = this.createWorker(); const messageHandler = this.createMessageHandler.bind(this); worker.onmessage = messageHandler; this.workerPool.push(worker); this.workerBusy.set(worker, false); this.messageHandlers.set(worker, messageHandler); } catch (error) { console.error('Failed to create worker:', error); break; } } console.log(`Initialized ${this.workerPool.length} workers`); } /** * 创建消息处理器 */ createMessageHandler(event) { const message = event.data; const worker = event.target; // 处理Worker就绪消息 if (message.type === 'ready') { console.log('Worker ready'); this.workerBusy.set(worker, false); return; } // 标记Worker为可用 this.workerBusy.set(worker, false); // 触发全局消息处理器 if (this.globalMessageHandler) { this.globalMessageHandler(event); } } /** * 设置全局消息处理器 */ setMessageHandler(handler) { this.globalMessageHandler = handler; } /** * 获取可用的Worker */ getAvailableWorker() { for (const worker of this.workerPool) { if (!this.workerBusy.get(worker)) { return worker; } } return null; } /** * 标记Worker为忙碌 */ markWorkerBusy(worker) { this.workerBusy.set(worker, true); } /** * 标记Worker为空闲 */ markWorkerIdle(worker) { this.workerBusy.set(worker, false); } /** * 向Worker发送消息 */ postMessage(worker, message, transferable) { if (transferable) { worker.postMessage(message, transferable); } else { worker.postMessage(message); } } /** * 检查是否有可用的Worker */ hasAvailableWorker() { return this.getAvailableWorker() !== null; } /** * 获取Worker池统计信息 */ getStats() { const total = this.workerPool.length; let busy = 0; for (const worker of this.workerPool) { if (this.workerBusy.get(worker)) { busy++; } } return { total, busy, idle: total - busy }; } /** * 销毁所有Worker */ destroy() { for (const worker of this.workerPool) { worker.terminate(); } this.workerPool = []; this.workerBusy.clear(); this.messageHandlers.clear(); this.globalMessageHandler = undefined; } /** * 🔧 检查是否支持 Web Worker */ isSupported() { return typeof Worker !== 'undefined' && typeof window !== 'undefined'; } } //# sourceMappingURL=WorkerManager.js.map