Deno 2.x与Bun:JS运行时之争

Node.js 已经统治 JS 服务端运行时十几年了,但 Deno 2.x 和 Bun 正在从不同角度发起挑战。这篇文章对比它们的特点、生态兼容性和性能表现。

三者定位

Node.js 是基石——最成熟的生态、最广泛的部署、最多的生产经验。缺点是历史包袱重(CommonJS/ESM 双模块系统、callback 遗产、安全模型缺失)。

Deno 2.x 由 Node.js 原作者 Ryan Dahl 创建,目标是「修正 Node.js 的设计错误」。2.x 版本做了重大转向——全面兼容 npm 生态,同时保留自身优势。

Bun 由 Jarred Sumner 创建,用 Zig 编写,核心卖点是「极致性能」。自带 bundler、test runner、package manager,追求 all-in-one。

Deno 2.x 的关键特性

npm 兼容性

Deno 2.x 最重要的变化是可以直接使用 npm 包,无需任何转换:

// 直接 import npm 包
import express from "npm:express";
import chalk from "npm:chalk";

const app = express();
app.get("/", (req, res) => {
    res.send(chalk.green("Hello from Deno!"));
});
app.listen(3000);

也支持 package.jsonnode_modules,这让现有 Node.js 项目迁移到 Deno 的成本大幅降低。

权限系统

Deno 的安全模型是其区别于 Node.js 的核心设计:

# 只允许网络访问和文件读取
deno run --allow-net --allow-read server.ts

# 细粒度控制
deno run --allow-net=api.example.com --allow-read=./data server.ts

# 2.x 新增:权限提示模式(开发时交互式询问)
deno run --prompt server.ts

在生产环境中,这个权限模型提供了额外的安全层——即使代码被注入恶意逻辑,没有对应权限也无法执行。

内置工具链

deno fmt          # 格式化(类似 prettier)
deno lint         # 代码检查
deno test         # 测试运行
deno bench        # 性能测试
deno compile      # 编译为单文件可执行程序
deno jupyter      # Jupyter notebook 支持

不需要 prettier + eslint + jest + pkg 这一堆工具,Deno 全部内置。

Bun 的关键特性

极致启动速度

Bun 用 JavaScriptCore(Safari 的 JS 引擎)替代 V8,在启动速度上有巨大优势:

# 空脚本启动时间对比(实测)
$ hyperfine 'node -e ""' 'deno eval ""' 'bun -e ""'

node:  32.1 ms
deno:  25.3 ms
bun:    6.2 ms

对于 CLI 工具和 serverless 函数,这个差距很有意义。

内置 Bundler

bun build ./src/index.ts --outdir ./dist --target browser

Bun 的 bundler 性能接近 esbuild,但原生支持 TypeScript 和 JSX,不需要额外配置。

包管理器

bun install          # 安装依赖,速度通常是 npm 的 10-20 倍
bun add express      # 添加依赖
bun remove lodash    # 移除依赖

Bun 的包管理器使用硬链接和全局缓存,安装速度远超 npm/yarn/pnpm。

性能对比

用一个简单的 HTTP server 做基准测试(hello world 响应):

// server.ts (兼容三个运行时)
const server = Bun?.serve?.({
    port: 3000,
    fetch(req) {
        return new Response("Hello World");
    },
}) ?? null;

// Node.js 和 Deno 用各自的 HTTP API

使用 wrk 测试(10 并发,30 秒):

运行时 请求/秒 平均延迟 P99 延迟
Node.js 22 62,400 0.16ms 0.42ms
Deno 2.3 89,100 0.11ms 0.31ms
Bun 1.2 128,300 0.08ms 0.22ms

Bun 在原始吞吐量上确实领先,但实际项目中瓶颈往往在数据库和外部 IO,HTTP 层的差距不会这么明显。

生态兼容性

这是决定能否在生产中使用的关键因素。

Deno 2.x 的 npm 兼容性已经很好,大部分 npm 包可以直接使用。少数依赖 Node.js 特定行为(如 monkey-patching require)的包可能有问题。在我的测试中,Express、Fastify、Prisma、Drizzle 都能正常工作。

Bun 的 Node.js API 兼容性在 1.x 后也大幅改善,但仍有一些边界情况。node:crypto 的部分实现不完整,一些依赖 native addon 的包需要重新编译。

我的选择建议

  • 新项目 + 看重安全性:Deno 2.x。权限系统是真正的差异化优势。
  • 新项目 + 看重性能:Bun。启动速度和运行性能都是最优。
  • 现有项目:继续 Node.js。迁移成本 > 收益,除非有明确的痛点。
  • 工具脚本/CLI:Bun。启动快,内置 TypeScript,写脚本最舒服。
  • Serverless/Edge:Deno。Deno Deploy 的开发体验很好,冷启动快。

三个运行时都在快速发展,竞争是好事。Node.js 也因此加速了改进——原生 TypeScript 支持、权限模型都已经在路线图上。