Worker 大数据排序需规避结构化克隆,用 SharedArrayBuffer/Transferable 零拷贝传数据,动态控制 Worker 数量与 chunk 大小,Worker 内手写计数排序,主线程用 k 路归并分帧执行,并及时释放内存和关闭 Worker。

直接用 postMessage() 传百万级数组进 Worker,基本等于自废武功——结构化克隆开销远超排序本身,页面不卡,但算得比单线程还慢。
Worker 传大数据前必须绕开结构化克隆
浏览器对 postMessage() 传递的普通数组、对象默认走结构化克隆,100万数字数组实测传输耗时常超 80ms。这不是 Worker 慢,是通信在拖后腿。
- 只传轻量标识:比如
{ chunkId: 2, range: [10000, 20000] },让 Worker 自己从SharedArrayBuffer或 IndexedDB 加载局部数据 - 用 Transferable 零拷贝:把数据预装进
Uint32Array等类型化数组,postMessage(arrayBuffer, [arrayBuffer])移交所有权 - 合并小结果:别每排完一块就发一次消息;归并阶段只传
{ start: 0, length: 50000 }这类元信息,主线程自己拼接
多 Worker 并行 ≠ 简单切数组 + for 循环
切块数不等于 CPU 核心数,更不能硬写死 numWorkers = 4。navigator.hardwareConcurrency 是参考值,低端设备可能只有 2,iOS Safari 常报 6 却实际调度乏力。
- 动态取整:用
Math.min(navigator.hardwareConcurrency || 2, 4)控制上限 - 每块数据量要压到 20 万以内:超限易触发 Chrome 的 Worker “无响应”警告,尤其在低内存安卓机上
- Worker 内部别用
arr.sort((a,b) => a-b)处理 50 万以上整数——V8 的 TimSort 在 Worker 中没做 JIT 优化,手写计数排序反而快 3 倍
主线程归并不只是 for 循环合并
把 N 个有序子数组暴力拼接再整体 sort(),就彻底白用了 Worker。归并逻辑写错,性能反降 40%。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
- 必须用 k 路归并:维护最小堆(可用
MinPriorityQueue库或手写),每次取各子数组首元素最小值,O(M log N) 时间复杂度 - 避免反复读写大数组:归并结果直接写入预分配的
Int32Array,别用push() - 主线程归并时也得让渡:若 N > 8,用
setTimeout(() => mergeNextChunk(), 0)分帧执行,防 UI 卡顿
Worker 内存不释放,跑三次就 OOM
Worker 没 GC 提示,let bigData = new Uint32Array(1e7) 排完不清理,下次任务一进来就内存溢出,DevTools 里连 warning 都不报。
- 排序完成后立刻
bigData = null,必要时加delete bigData - 每个 Worker 实例处理完主动
self.close(),别等主线程 terminate —— 后者不保证立即回收 - 加心跳检测:Worker 内每 500ms
self.postMessage({ type: 'ping' }),主线程超时未收则重建
真正卡住用户的从来不是算法复杂度,而是通信方式选错、内存没清、chunkSize 硬编码——这些细节不调,开 10 个 Worker 也快不过一个 Array.sort()。


















