![]()
JavaScript 统治前端开发15年,但一个老问题始终没解决:CPU 密集型任务会让页面直接卡死。算个斐波那契数列,主线程就冻结,用户体验瞬间归零。
Worker 线程(网页多线程技术)本该是解药,但原生 API 写起来像在做手工活——创建文件、发消息、收消息、手动同步。一个简单计算要拆成三四个文件,心智负担极高。
GitHub 上有个叫 puru 的库,把这套流程压到了5行代码。不是语法糖,是把线程管理的机械复杂度整个抽走了。
原生 Worker 的"手工活"困境
算第40个斐波那契数,原生写法要先建一个 fib.js 文件,里面放计算逻辑。主线程创建 Worker 实例,postMessage 发参数,onmessage 等结果。
三个步骤,两个文件,消息来回一趟。代码量不多,但上下文切换频繁——你刚在主线程写业务逻辑,突然要切到另一个文件里想线程通信的边界问题。
puru 的做法是直接传函数:spawn(() => fibonacci(40)),然后 await 结果。函数被自动序列化到 Worker 里执行,开发者不用碰文件系统。
这个抽象有个硬性代价:函数不能捕获外部变量。闭包里的数据传不进去,因为 Worker 是进程级隔离,不是线程级共享。puru 把这个限制摆到明面上,反而避免了隐蔽的状态共享 bug。
结构化并发:从 Promise.all 到生产级流水线
Promise.all 能并行多个异步任务,但遇到 CPU 密集型流水线就露怯了。四个 Worker 同时消费数据,怎么协调输入输出?怎么防止死锁?怎么控制内存不爆?
puru 搬来了 Go 语言的 channel 和 WaitGroup。channel 是带缓冲的队列,生产者往里塞,消费者往外取,中间有背压机制——缓冲区满了就阻塞,不会无限堆积。
代码长这样:先建两个 channel,一个输入一个输出,各50个缓冲位。然后循环 spawn 四个 Worker,每个从输入 channel 取数,平方后送进输出 channel。
缓冲大小是开发者自己定的。太小会频繁阻塞,太大吃内存。puru 不替你猜,把权衡暴露出来,这和 Rust 的显式错误处理一个路数。
不是银弹,但填补了生态空白
没有这类工具,JS 开发者只有两条路:要么忍受主线程卡顿,要么自己造轮子。前者产品体验差,后者维护成本高。
puru 的约束很清晰:函数序列化、无闭包、手动调缓冲。这些不是缺陷,是 Worker 模型的物理限制被翻译成了 API 设计。
项目还在早期,但解决的是一个真实痛点——JS 生态里缺一把趁手的 Worker 工具。不是让多线程变简单,是让"简单任务的多线程"不再复杂。
你在生产环境用过 Worker 线程吗?最后是自己封了一套,还是干脆避开 CPU 密集型场景了?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.