将复杂数据结构运算移入Worker线程是保障主线程60FPS最可靠方式,需确保传纯数据、用Transferable零拷贝、主动分片反馈进度、结果在Worker内聚合、任务结束立即销毁线程。

把复杂数据结构运算放进 Worker 线程,是守住主线程 60FPS 最可靠的做法。关键不在“算不算得动”,而在“传得准、分得细、回得稳、收得干净”。
只传纯数据,不传逻辑或上下文
Worker 无法访问主线程的函数、类实例、闭包或 DOM 对象。所有输入必须是可结构化克隆的值:
- 支持:普通对象、数组、TypedArray(Float64Array、Uint8ClampedArray)、字符串、数字、Date、ArrayBuffer
- 不支持:function、class 实例、Promise、RegExp(行为不稳定)、canvas.getContext 等
- 举例:不要传
calculate({ a, b }, Math.sqrt);改用描述式结构,如{ type: 'sqrt_sum', values: [1.2, 3.7, ...] }
大数组用 Transferable 零拷贝传输
当运算涉及万级以上的数值(如矩阵、时间序列、图像像素),避免深拷贝带来的延迟和内存压力:
- 主线程创建
const buffer = new Float64Array(5e5).buffer - 发送时带上 transfer 列表:
worker.postMessage({ data: buffer }, [buffer]) - Worker 内直接复用:
const arr = new Float64Array(event.data.data),无需复制内存 - 多次任务可复用同一 buffer,比反复 new 更稳定
主动分片 + 进度反馈,防单帧超时
任何单次计算超过 16ms(≈1/60 秒)就可能丢帧。对迭代、递归或批量处理类运算,必须切片并上报进度:
- 主线程发任务时明确 chunkSize,例如:
{ type: 'mergeSort', array: buffer, chunkSize: 2048 } - Worker 每完成一个 chunk,调用
self.postMessage({ type: 'progress', done: 4096 }) - 主线程监听
message事件,区分type === 'progress'和'result',更新 UI 进度条或骨架占位
结果聚合在 Worker 内完成,不甩锅给主线程
避免主线程收到几千个中间结果再合并——这又会引发新卡顿:
- Worker 应负责全部归并逻辑,例如:对分块排序结果做 k-路归并,或对蒙特卡洛采样结果求均值与方差
- 最终只返回一个轻量对象:
{ result: finalValue, stats: { min, max, count } } - 若需部分结果预览(如图表渲染前 10% 数据),可额外加
type: 'preview'类型消息
任务结束立即销毁,不遗留空转线程
Worker 不会自动退出,长期驻留会持续占用内存并干扰调度:
- 主线程在收到
type: 'result'后,立刻执行worker.terminate() - Worker 自身也可在计算完毕后调用
self.close(),确保彻底释放 - 务必监听
worker.onerror,捕获未处理异常,防止静默失败导致界面无响应
不复杂但容易忽略。











