学径XUEJING · 个人学习平台通知设置

课程库 技术雷达 语言与运行时 › 第 2

Bun —— JavaScript 运行时的第三次内卷

普通课35 分钟

本课导读

你每天敲 npm run dev 启动本站项目时,代码其实跑在 Node.js 上。Bun 是 2022 年冒出来的挑战者,口号是"把 Node、npm、打包器、测试框架全换成我,还快几倍"。本课先补一块地基——"JS 引擎"和"JS 运行时"到底是什么关系(搞懂这个,Node/Deno/Bun 的一切八卦都能听懂了)——再讲清 Bun 凭什么快、你现在该不该用。预计 35 分钟。

地基:引擎 vs 运行时

JavaScript 这门语言自己不会读文件、不会开网络端口、连 console.log 都不是语言标准的一部分。语言规范只定义了语法、对象、Promise 这些"纯计算"的部分。真正让 JS 代码动起来的是两层东西:

第一层:引擎(Engine)——负责"纯计算"的执行器,把 JS 源码变成机器指令。世界上主要有三个,全是浏览器大战的产物:

引擎出身用在哪
V8Google,为 Chrome 开发Chrome、Node.js、Deno
JavaScriptCore(JSC)Apple,为 Safari 开发Safari、Bun
SpiderMonkeyMozillaFirefox

第二层:运行时(Runtime)——引擎 + 一整套"跟外部世界打交道"的 API + 事件循环调度。浏览器是一种运行时(提供 DOM、fetch、localStorage);Node 是另一种运行时(提供 fs 读写文件、http 开服务器、process 环境变量)。

提示

类比:引擎是发动机,运行时是整车。V8 这台发动机装进 Chrome 就是浏览器,装进 Node 就是服务器运行时——同一台发动机,配的"轮子和方向盘"(API)完全不同。所以浏览器里没有 fs(不能让网页随便读你硬盘),Node 里没有 document(服务器上没有网页 DOM)。

三代运行时的恩怨史

Node.js(2009):Ryan Dahl 把 V8 从浏览器里拆出来、配上文件/网络 API——JS 从此能写服务器,前后端一门语言,直接催生了如今整个 npm 生态。你项目的一切(Next.js、ESLint……)都长在 Node 上。

Deno(2018):还是 Ryan Dahl,发表著名演讲《我对 Node 的十大后悔》后另起炉灶:默认禁止读文件/联网(安全沙箱)、原生跑 TypeScript、内置工具链。理念先进,但跟 npm 生态兼容不佳,起步艰难(后来妥协支持了 npm 包)。

Bun(2022):Jarred Sumner 用 Zig(一门 C 级别的系统语言,和 Rust 同一生态位的极简派)从零写的运行时,换用 Apple 的 JSC 引擎。它吸取了 Deno 的教训,把兼容性放在第一位:目标是 Node 的原地替换(drop-in replacement)——你的项目不改代码,理论上直接 bun run 就能跑。

Bun 的两张牌

第一张牌:快。 快在三处——运行时本身用 Zig 手工优化、JSC 启动比 V8 更快、以及最有体感的:bun install 装依赖比 npm 快几倍到几十倍(重写了整个安装器:并行下载、二进制 lockfile、全局缓存硬链接)。

第二张牌:all-in-one。 Node 时代你需要拼装一堆工具,Bun 全部内置:

你现在用的Bun 内置的
node(运行时)bun run
npm(包管理)bun install
jest / vitest(测试)bun test
esbuild / webpack(打包)bun build
ts-node(跑 TS)原生支持,直接 bun index.ts
Bash
# 体验一下"全家桶"的画风(Windows 上装 Bun:powershell -c "irm bun.sh/install.ps1 | iex")

bun init          # 初始化项目(替代 npm init)
bun install       # 装依赖(读的就是 package.json,秒级完成)
bun run dev       # 跑 package.json 里的脚本(替代 npm run dev)
bun index.ts      # 直接运行 TS 文件,不用配置任何编译
bun test          # 跑测试,Jest 兼容语法

写个 HTTP 服务器感受下 API 风格(Bun 自带顶层 Bun 全局对象):

TypeScript
// server.ts —— 用 Bun 起一个 HTTP 服务器,零依赖零配置
// (Node 里同样的事要 import http 然后写一堆样板代码)
Bun.serve({
port: 3000,
fetch(req) {
  return new Response("Hello from Bun!");
},
});

console.log("跑起来了:http://localhost:3000");
// 运行:bun server.ts

注意 fetch(req) 返回 Response——Bun(和 Deno)尽量复用浏览器已有的 Web 标准 API(Request/Response/fetch),而不是像 Node 早期那样发明自己的一套。这是新一代运行时的共同审美:一门语言,一套 API,浏览器和服务器通用。

冷静区:该不该换?

兼容性现状:Bun 实现了绝大部分 Node API,多数 npm 包能直接跑,但"绝大部分"不是"全部"——一些依赖 Node 底层细节的包(原生插件、罕见 API)会踩坑。Next.js 这类重型框架官方生产支持仍以 Node 为准

给你的实用建议(按风险从低到高):

  1. 今天就能用:拿 Bun 当"更快的 npm"——bun install 只是装依赖,装完照常用 Node 跑,纯提速不改运行时,风险约等于零
  2. 随手可用:写一次性脚本、小工具时 bun xxx.ts 直接跑 TS,省去所有配置
  3. 再等等:把生产环境的 Next.js 运行时换成 Bun——收益不明显(瓶颈通常不在运行时),风险却真实存在

注意

听到"X 比 Y 快 30 倍"时永远追问一句:快在哪个环节,那个环节是我的瓶颈吗? bun install 快 20 倍是真的,但你一天装几次依赖?你网站的慢来自数据库查询和网络往返,换运行时救不了。识别 benchmark 营销,是读懂技术圈的基本功。

够用判断线

下次群里聊 Bun,你的知识储备:Bun = Zig 写的 Node 替代品,用 JSC 引擎,主打快和全家桶,兼容 npm 生态,装依赖是它最无痛的入口。什么时候值得深入:你开始频繁写独立的 TS 脚本/小服务(Bun 的零配置体验是真香),或者你的团队被 CI 装依赖的速度逼疯了。

随堂测验

随堂测验0 / 4 题正确

1. 「JS 引擎」和「JS 运行时」的关系,下列哪个说法正确?

2. 为什么浏览器里的 JS 不能像 Node 那样直接读写你电脑上的文件?

3. Bun 相比前辈 Deno,起步阶段少踩的最大的坑是什么?

4. 对你的 Next.js 项目而言,现阶段引入 Bun 风险最低、收益最直接的方式是?

划选正文任意文字可高亮、批注或加入复习卡

讨论

载入中…