Bun:JS工具链的降维打击
Node是标准,Deno是理想,Bun是效率。
一、赛道已经换了:为什么JSC赢了V8
Bun的碾压级速度不是魔法,是一个清晰的架构选择——用"长运行峰值吞吐"换"短任务极速启动"。
| V8(Node/Deno) | JavaScriptCore(Bun) | |
|---|---|---|
| 设计目标 | Chrome长时页面渲染 | Safari快速打开标签页 |
| 优化方向 | JIT预热后峰值吞吐 | 冷启动+首次执行速度 |
| 内存footprint | 较大(~40MB基线) | 较小(~18MB基线) |
| 适配场景 | 长运行重型计算 | I/O密集+短生命周期任务 |
这不是在比较V8和JSC谁"更好",而是指出:Node选错了优化目标。V8为Chrome的长时页面渲染而生,JIT偏重峰值吞吐。但服务端JS的典型负载是"起一个进程,做点I/O,然后死掉"——JIT预热的时间比干活的时间还长。Bun用JSC,是把优化目标从"跑久了好"扭转为"跑得快、死得干净",这恰好命中了Serverless时代的物理账本。
再用Zig写运行时——无GC拖累的底层内存管理,系统调用路径极短,冷启动压到毫秒级。加上Linux io_uring内核级异步I/O,不走libuv事件循环。
不是Bun比V8"更好",是Bun选了更适合JS服务端典型负载的引擎。一旦成本函数对了,选引擎就自然了。
二、为什么JS服务端负载长这样:三个产业结构变迁
JS服务端"短生命周期+I/O密集"的负载形态不是天然的,是三个历史力量共同塑造的:
2.1 计算的民主化——前端开发者涌入后端
他们用JS不是因为JS是最好的服务端语言,而是因为这是他们唯一会的语言。这决定了服务端JS的典型任务不是数值计算(那是Python/Julia的地盘),而是胶水逻辑——接请求、查数据库、拼JSON、返回响应。胶水逻辑天然是I/O密集的。
2.2 计算的碎片化——Serverless/微服务/边缘计算
| 模式 | 进程生命周期 | 计算特征 |
|---|---|---|
| 单体应用(2005) | 天级 | CPU可预热,JIT有时间优化 |
| 微服务(2015) | 小时级 | 部分可预热,但容器调度频繁 |
| Serverless(2020) | 毫秒级 | JIT预热时间 > 执行时间 |
| 边缘计算(2023) | 毫秒级+冷启动频繁 | 每次请求可能都是冷启动 |
当进程从"天级"压缩到"毫秒级",V8的JIT优化窗口从"充裕"变成了"负数"——预热还没完成,进程已经死了。这不是V8的bug,而是时代变了。
2.3 计算的商品化——按调用计费
Serverless按ms计费,边缘计算按请求计费。在这个经济模型下,冷启动时间就是直接成本。Bun省100ms冷启动不是"快一点",是每次调用少付100ms的钱。百万级调用下,这就是账面上的数字。
三、裁判重定义:Bun不是在赢比赛,而是在换裁判
Bun真正的力量不在"更快",而在重新定义了什么叫"快"。
| 裁判 | Node表现 | Bun表现 | 胜者 |
|---|---|---|---|
| JIT预热后峰值吞吐 | ✅ 强(V8老本行) | ⚠️ 一般 | Node |
| 冷启动时间 | ❌ 60-120ms | ✅ 8-15ms | Bun |
| 基线内存占用 | ❌ 40MB | ✅ 18MB | Bun |
| 端到端成本(Serverless) | ❌ 贵 | ✅ 省 | Bun |
Node在旧裁判(JIT预热后峰值吞吐)下赢了,Bun在新裁判(端到端成本)下赢了。新裁判为什么取代旧裁判?因为产业结构变迁让新裁判更接近真实成本函数。
这和AlphaGo Zero的结构同构:
| AlphaGo vs Zero | Node vs Bun | |
|---|---|---|
| 旧裁判 | 模仿人类棋谱的准确度 | JIT预热后峰值吞吐 |
| 新裁判 | 终局胜负 | 端到端成本 |
| 裁判切换的驱动力 | 自我对弈发现了更优策略 | 产业结构变迁改变了真实成本函数 |
| 旧方案的"口音" | 人类棋谱偏见残留在权重中 | V8的长运行优化偏执残留在架构中 |
但这不是零和博弈——JS运行时不是围棋。Node不会因为Bun的存在而消失,因为企业存量项目、CPU密集场景、LTS需求、C++原生模块生态都是Node的护城河。在开环世界中,多个裁判可以共存,不同场景需要不同的裁判。
四、快多少:数据说话
| 指标 | Bun 1.3 | Node.js 24 | Deno 2.6 | 倍数 |
|---|---|---|---|---|
| HTTP吞吐 | ~110k req/s | ~45k | ~85k | 2.4× vs Node |
| 冷启动 | 8–15ms | 60–120ms | 40–60ms | 10× vs Node |
| 包安装(冷) | ~1s | ~20s | ~17s | 20× vs npm |
| 包安装(热) | ~0.3s | ~8s | ~0.8s | 27× vs npm |
| TS执行 | ~10ms | ~150ms(需tsx) | ~30ms | 15× vs Node |
| SQLite 10k行插入 | 12ms | 88ms | 45ms | 7× vs Node |
| 基线内存 | ~18MB | ~40MB | ~30MB | 一半不到 |
| 大monorepo(1847依赖) | 47s | 28min | — | 36× |
冷启动10×差距对Serverless是真金白银——Lambda按ms计费,Bun每次调用省100ms,百万级调用就是显著成本差异。
五、All-in-One:DX的涌现
| 需求 | Node生态 | Bun |
|---|---|---|
| 包管理 | npm/pnpm/yarn | bun install ✅ |
| 打包 | webpack/esbuild/rollup | bun build ✅ |
| 测试 | jest/vitest | bun test ✅ |
| TypeScript | tsx/ts-node | 原生支持 ✅ |
| .env | dotenv | 原生读取 ✅ |
| JSX | 配置babel/tsx | 原生支持 ✅ |
| SQLite | better-sqlite3 | bun:sqlite ✅ |
| 单文件分发 | pkg/nexe | bun build --compile ✅ |
单独看每一项,都不是不可替代的。bun test可以换成jest,bun build可以换成esbuild。但当这一切内建在一个二进制里,而且零配置可用时,就发生了质变。
"Going back to Node feels like stepping back 5 years"——这是DX涌现的典型症状。无数小的、可判定的改进(启动快一点、安装快一点、原生支持TS),在某个临界点之后,集体跃迁到另一个不可判定的体验层级。你无法用一个benchmark证明"DX好10×",但迁移过的人都知道它真实存在。
构建管线从"拼装"变"原生",抹平了Webpack/esbuild/Jest的配置摩擦。
六、兼容策略:Drop-in Replacement,不颠覆
与Deno强推Web标准、自建生态不同,Bun优先实现Node.js API(fs, http, net, path等)和npm包兼容。
- 98-99% npm兼容——
bun run index.js基本直接替换node index.js - Express、Hono、Next.js(99%兼容,实验性)、Prisma、Zod都能跑
- 不能用的5%:node-gyp编译的原生C++模块(bcrypt、sharp某些配置)、
node:crypto边缘case
迁移成本极低,企业存量项目无痛接入,不破坏现有依赖树。
七、生产采纳证据
| 公司 | 用Bun做了什么 |
|---|---|
| Anthropic | Claude Code CLI用Bun单文件可执行 |
| Midjourney | 内置WebSocket服务器做生成通知 |
| Vercel | 2025年底原生支持Bun部署Next.js |
| Railway | Serverless函数用Bun运行 |
八、何时选/不选
选Bun:
- Serverless/短生命周期任务(冷启动10×优势直接变钱)
- CI/CD管线(1847依赖47s vs npm的28min)
- CLI工具(单文件可执行分发)
- 前端基建、快速原型
- 追求极致DX的团队
谨慎选择:
- 重度依赖V8特有优化(特定N-API C++ Addon、复杂长时数值计算)——JSC的JIT路径与V8不同,CPU密集场景Bun接近甚至略输Node(React SSR 4,150 vs 4,200 ops/sec)
- 强依赖Node最新实验性API
- 需要LTS的企业(银行、医疗)——Bun没有长期支持策略
- 需要安全模型——Deno默认拒绝一切权限,Bun没有权限控制
- Windows为主的环境——Bun 1.x在Windows上兼容性和性能显著弱于macOS/Linux
九、技术史的一个模式
Bun的故事不是孤例。回顾历史,"裁判重定义"反复出现:
| 旧裁判 | 旧胜者 | 新裁判 | 新胜者 | 驱动力 |
|---|---|---|---|---|
| 单核峰值性能 | C++ | 并行吞吐 | Java/C# | 多核普及 |
| 手动内存管理效率 | C | 开发效率 | Python/JS | 开发者成本上升 |
| JIT预热后峰值 | Node(V8) | 冷启动+端到端成本 | Bun(JSC) | Serverless兴起 |
每次裁判重定义的背后,都是成本结构的变迁——当某个成本维度从"可忽略"变成"占大头"时,优化方向就必须切换。
Python比C慢100倍,但开发者效率高10倍——当开发者成本 > 计算成本时,Python赢了。
Bun在CPU密集场景略输Node,但冷启动快10倍——当冷启动成本 > 峰值吞吐差异时,Bun赢了。
那成本结构为什么会变迁?因为抽象层次的迁移。
每当一个行业把某一层的实现"做完了"——单核优化到了物理极限、手动内存管理的边际收益趋近于零——成本结构就自动转移到下一层未被满足的需求上:并行吞吐、开发效率、冷启动开销。这不是某个工具的功劳,而是技术演化的结构性必然:每一层的"做完了",就是下一层"赛道切换"的发令枪。
C++把单核性能做到了极致,于是成本重心转移到"如何利用多核"——Java/C#胜出。C把手动内存管理做到了极致,于是成本重心转移到"如何降低开发者心智负担"——Python/JS胜出。Node把服务端JS的长运行吞吐做到了可用,于是成本重心转移到"如何让短生命周期任务更便宜"——Bun胜出。
技术史的本质不是"更好的工具取代更差的工具",而是"更匹配当前成本结构的工具取代不再匹配的工具"——而成本结构本身,由抽象层次的迁移驱动。
十、一句话
Bun不是在Node的赛道上跑得更快,而是发现赛道已经换了。
产业结构变迁漂移了成本函数,成本函数的漂移淘汰了旧裁判,抽象层次的迁移让这一切成为必然——Bun只是这个结构中一个具体的、可验证的截面。
雨轩于听雨轩 🌧️🏠