打开网易新闻 查看精彩图片

GitHub上有个78星的仓库,Star数少得可怜,但点进去的人多半会愣住——这代码长得太像Rust了。不是借鉴,是像素级复刻:channel、spawn、select、oneshot,连panic处理都搬过来了。开发团队Rivet的注释写得直白:「说实话,你现在肯定更想写Rust,但世界运行在JS上。」

这话扎了不少前端的心。TypeScript写了这么多年,Promise.all、AbortController、setTimeout手动拼来拼去,取消逻辑和竞态条件像定时炸弹。Antiox(Antioxidant的缩写,抗氧化——意思是防止你的异步代码「氧化」腐烂)把Tokio的结构化并发原语整套端进了JS运行时。

「手写Promise.all等于给自己埋雷」

「手写Promise.all等于给自己埋雷」

Rivet团队算过一笔账:手动组合Promise.all、AbortController和setTimeout,边缘情况的数量是指数级增长的。取消时机对不对?资源释放顺序乱没乱?多个定时器嵌套时谁覆盖谁?这些问题在Rust里由Tokio的编译期保证解决,在JS里只能靠程序员自己盯。

打开网易新闻 查看精彩图片

Antiox的解法很粗暴——让JS代码长得像Rust。channel对应Tokio的mpsc(多生产者单消费者通道),spawn启动的任务自带结构化生命周期,select可以同时监听多个异步源并处理先到者。最狠的是unreachable函数,传入一个never类型参数,能在编译期就掐死switch语句的漏分支。

代码示例里的Actor模式很说明问题:一个计数器任务通过channel接收消息,increment和get两种操作类型用联合类型锁死,resTx(oneshot通道的发送端)保证单次响应。整个系统没有回调地狱,没有EventEmitter的内存泄漏隐患,关闭时rx迭代器自然结束,资源自动回收。

零依赖、可摇树、LLM友好

零依赖、可摇树、LLM友好

Antiox的package.json干净得反常:dependencies字段是空的。所有模块都做成可摇树(tree-shakeable),用多少打包多少。Rivet在README里强调「没有自定义DSL,没有包装类型,没有不必要的内存分配」——这三句话几乎是在点名批评某些「轻量级」异步库,加个功能就给你塞一整套运行时。

打开网易新闻 查看精彩图片

命名和结构完全对齐Tokio还有个隐藏好处:大语言模型对Rust/Tokio的训练数据极多,提示词里写「用Antiox实现一个背压限流的批量处理器」,LLM基本能猜对API。反过来,如果你让AI写「用某个国产异步库实现同样功能」,它可能先 hallucinate 出一堆不存在的API。

目前API标注为Pre-release,但Rivet明确说「已在生产环境使用」。这意味着稳定性有保障,接口可能微调。对于想在Node.js或Deno里写高并发服务、又不想切到Rust重新造工具链的团队,这是个务实的中间态。

「世界运行在JS上」的潜台词

「世界运行在JS上」的潜台词

Rivet那句大实话背后有个尴尬现实:Rust异步生态确实先进,但业务代码跑在V8上是硬约束。Antiox不是让JS变成Rust,是把Rust的并发思维模式移植过来——channel替代共享状态,任务替代裸Promise,结构化并发替代手动cleanup。

这种移植有代价。JS没有所有权系统,Antiox能在运行期做的检查有限;JS的异常模型和Rust的Result类型也不完全对应。但相比手动拼装Promise.all的混沌状态,有约束总比没约束强。

78个Star的数字还在涨。评论区有人调侃:「终于不用在代码review时解释为什么某个setTimeout不能删了。」另一条反馈更实在:「我们拿它重构了消息队列的消费者,内存占用降了40%,主要是终于能确定任务什么时候真的结束了。」