5月28日 02:54

Bun 为什么比 Node.js 快?底层架构与性能优化全解析

Bun 是由 Jarred Sumner 创建的全能型 JavaScript 运行时,自 2022 年发布以来凭借惊人的启动速度和 HTTP 吞吐量迅速赢得开发者关注。官方基准测试显示,Bun 的启动时间仅 8-15ms,是 Node.js(60-120ms)的 5-12 倍;HTTP 请求处理达 11 万 QPS,远超 Node.js 的 4.5 万 QPS。2025 年底 Anthropic 收购 Bun 后,其冷启动优势成为 Claude Code 等 AI 工具的核心基础设施。这种高性能并非偶然,而是底层架构设计哲学的直接产物:选用 JavaScriptCore 替代 V8、用 Zig(后迁移 Rust)实现零开销抽象、将运行时/包管理/打包/测试四合一。本文将拆解 Bun 性能优势的每一个技术支柱。

JavaScriptCore:比 V8 更快的启动引擎

Bun 性能优势的第一根支柱是选择了 Apple 的 JavaScriptCore(JSC)而非 Google 的 V8 作为 JavaScript 引擎。这个选择直接决定了 Bun 的启动速度优势。

JavaScriptCore 是 Safari 的 JS 引擎,与 Chrome/Node.js 使用的 V8 有着根本不同的优化策略:

  • 更快的启动编译:JSC 的解释器和 JIT 编译器启动开销远低于 V8。V8 需要先解释执行代码、收集类型反馈,再由 TurboFan 编译优化,这个过程在短生命周期脚本中成本高昂。JSC 则采用更轻量的分层编译策略,冷启动更快。
  • 更低的内存基线:JSC 的初始内存占用比 V8 低约 30%。对于 Serverless 场景中频繁冷启动的函数,这意味着更少的资源浪费和更低的费用。
  • Safari Web API 原生复用:Bun 直接复用了 JSC 中已实现的 Web 标准 API(如 fetch、WebSocket、ReadableStream),避免了从零实现的工程成本和性能损耗。

Bun 的作者 Jarred Sumner 明确表示,选用 JavaScriptCore 是 Bun 速度的两大关键因素之一。

Zig 语言:手动内存管理与编译期计算

Bun 最初完全用 Zig 编写,这是性能优势的第二根支柱。Zig 的选择并非追逐潮流,而是基于以下技术考量:

手动内存管理消除 GC 暂停

Zig 没有隐式垃圾回收,所有内存分配由开发者显式控制。Bun 团队为此编写了高度优化的自定义分配器:

  • 热路径零分配:在 HTTP 请求处理、文件 I/O 等关键路径上,Bun 通过预分配内存池和对象复用避免了运行时动态分配,消除了 GC 暂停。
  • 精确的内存生命周期:Zig 的 defererrdefer 语法让资源释放时机一目了然,内存泄漏风险远低于手动 malloc/free

Comptime 编译期代码生成

Zig 的 comptime 能力是性能利器——在编译期执行代码并生成高度特化的机器码:

zig
// 编译期生成特化的解析函数 fn Parser(comptime T: type) type { return struct { pub fn parse(input: []const u8) ?T { // 编译期根据 T 生成专用解析逻辑 } }; }

Bun 的 JSX/TypeScript 转译器大量使用 comptime 特化,避免运行时分支判断,这是其转译速度远超 Babel/swc 的原因之一。

与 C 生态的无缝互操作

Zig 可以直接 @cImport C 头文件而无需 FFI 绑定层。Bun 利用这一点直接调用 JavaScriptCore 的 C API,调用开销接近零,而 Node.js 通过 N-API 调用 C++ 则需要经过多层封装。

四合一架构:消除进程间通信开销

Bun 将运行时、包管理器(bun install)、打包器(bun build)、测试运行器(bun test)整合在单一二进制文件中,这是性能优势的第三根支柱。

传统 Node.js 开发需要 Node.js + npm/yarn + webpack/esbuild + Jest 多个进程协同工作:

  • 进程启动开销:每个工具独立启动,重复加载 V8 和基础库。
  • IPC 通信成本:工具间通过管道或临时文件传递数据,序列化/反序列化开销显著。
  • 重复解析:TypeScript 代码被不同工具反复解析多次。

Bun 的四合一架构让所有工具共享同一个 JavaScriptCore 实例和 AST:

bash
# 一个二进制完成所有工作 curl -fsSL https://bun.sh/install | bash bun init # 初始化项目 bun install # 安装依赖(比 npm 快 30 倍) bun test # 运行测试(比 Jest 快 3 倍) bun build ./src/index.ts --outdir=dist # 打包

包管理器的性能差异尤为明显:Bun install 对中型项目的冷安装约 1 秒,而 npm 需要 20 秒。原因在于 Bun 仅执行约 16.5 万次系统调用,而 npm 执行近 100 万次,同时 Bun 使用硬链接避免重复下载。

内置数据库与 I/O 优化

Bun 1.2 引入了内置数据库支持,直接在运行时层面优化 I/O:

bun:sqlite 同步 API

Bun 内嵌了 SQLite 并提供同步 API。在 Node.js 中访问 SQLite 需要通过 better-sqlite3 的 C++ 绑定跨越 JS/C++ 边界,而 Bun 的 SQLite 操作直接在 Zig 层完成:

typescript
import { Database } from "bun:sqlite"; const db = new Database(":memory:"); const stmt = db.prepare("SELECT * FROM users WHERE id = ?"); // 同步调用,无 Promise 开销 const user = stmt.get(42);

内置 PostgreSQL 与 S3 客户端

Bun 1.2+ 还内置了 Bun.SQL(PostgreSQL 客户端)和 S3 客户端,减少了外部依赖和网络中间层。

Zig 到 Rust 的迁移:2026 新篇章

2025 年 12 月 Anthropic 收购 Bun 后,团队启动了从 Zig 到 Rust 的大规模迁移。2026 年 5 月,68% 的代码库(96 万行)在 6 天内完成重写,达到 99.8% 测试兼容性。

迁移的技术动机:

  • Rust 的所有权模型消除手动内存管理导致的内存泄漏问题。重写后 Bun 运行时中的内存安全缺陷大幅减少。

  • AI 辅助开发更友好:Anthropic 的 AI 工具对 Rust 的理解和生成能力远强于 Zig,这是迁移的重要推动力。Zig 社区的反 AI 立场与 Anthropic 的技术路线冲突。

  • 生态与社区:Rust 拥有更成熟的工具链(Cargo)和更丰富的库生态,有利于长期维护。

迁移后的性能表现:HTTP 吞吐量提升至 Node.js 的 4 倍,但社区也对 AI 快速重写引入的 13000+ 个 unsafe 块和部分测试修改提出了质量担忧。

实战:Bun 性能优化的最佳实践

适合 Bun 的场景

  • Serverless / Edge Function:冷启动 8-15ms,是 Node.js 的 1/10,直接降低云函数延迟和费用。
  • 高频 HTTP 服务:11 万 QPS 的吞吐量适合 API 网关和微服务。
  • CI/CD 流水线bun install 比 npm 快 30 倍,bun test 比 Jest 快 3 倍,显著缩短构建时间。
  • TypeScript 开发:零配置运行 TS,无需 ts-nodetsc 预编译。

注意事项

  • 生态兼容性:Bun 通过了 98% 的 Node.js 测试套件,但少数 N-API 原生模块可能存在兼容问题,迁移前需验证。
  • 内存模型差异:Bun 的内存管理策略与 Node.js 不同,长时间运行的进程需关注内存增长趋势,可使用 Bun.gc() 手动触发回收。
  • Rust 迁移过渡期:当前处于 Zig→Rust 迁移期,部分功能可能存在两个实现并行的情况,建议关注官方发布日志。

快速上手

bash
# 安装 curl -fsSL https://bun.sh/install | bash # 创建项目 bun init # 运行 TypeScript bun run src/index.ts # 启动 HTTP 服务 bun run server.ts # 支持 Bun.serve() # 性能基准测试 bun bench

Bun 证明了 JavaScript 运行时可以同时做到快速启动、高吞吐和低内存占用——关键在于从引擎选择、实现语言到架构设计的每一层都做出有利于性能的决策。随着 Rust 迁移的推进,Bun 正从实验性工具走向生产级基础设施。

标签:Bun