Web Worker 中应封装基于最小堆的优先队列调度器,实现任务排队、优先级执行、空闲感知、错误隔离及 taskId 双向映射。

在 Web Worker 中封装统一的任务调度器,核心不是让 Worker “更聪明”,而是让它“更守序”——主线程只管发任务,Worker 自己管排队、判优先、选执行、报结果。关键在于把 FIFO 队列换成可排序的优先队列,并让调度逻辑内聚在 Worker 内部,不依赖外部干预。
用最小堆实现带优先级的任务队列
Worker 默认用消息事件队列(FIFO),无法跳过低优任务。需在 Worker 脚本中自行维护一个最小堆(数值越小,优先级越高),支持 O(log n) 入队和出队:
- 每个任务对象至少含 id、priority(如 -10 表示 immediate,0 为 normal,100 为 background)、payload 和 type
- 入队时调用
heap.enqueue(task, task.priority),自动按 priority 排序;出队始终取最高优(堆顶) - 避免用数组
sort()实现——每插入一次就全排序,任务量大时性能骤降
调度循环与空闲感知结合
仅靠优先级还不够:高优任务多时仍可能挤占所有时间,导致低优任务长期饿死。应在 Worker 内部引入节制机制:
- 用
self.onmessage接收任务后,不立即执行,而是enqueue到堆中 - 启动一个轻量调度循环(如
requestIdleCallback包裹的runNextTask),每次只执行一个任务,且检查deadline.timeRemaining() > 2才继续 - 若当前无高优任务,可主动降级执行中等优先级任务;连续空闲超 30ms 后,才允许执行 background 类型
任务状态管理与错误隔离
Worker 是单线程环境,一个任务崩溃会导致整个 Worker 挂掉。必须把执行包装成受控单元:
- 每个任务用
try/catch包裹,失败后通过self.postMessage({ id, error: e.message })上报,不中断调度循环 - 记录当前运行任务 ID,执行完成或超时后清除;超时阈值建议由主线程传入(如
{ timeout: 8000 }) - 支持重试字段(
retry: 2),失败后自动按原优先级重新入队,但限制最大重试次数防死循环
主线程交互需双向绑定 taskId
Worker 不知道谁发的任务,主线程也不知道哪条结果对应哪个请求。必须靠唯一 taskId 建立映射:
- 主线程提交前生成
const taskId = Date.now() + '-' + Math.random().toString(36).substr(2, 9) - 发送消息时带
{ taskId, priority, payload };Worker 处理完回传同样taskId - 主线程用
Map缓存pendingTasks.set(taskId, { resolve, reject }),收到响应即触发对应 Promise

















