Bun 性能优化
Bun 本身已经非常快速,但通过正确的优化策略可以进一步提升性能。本章介绍 Bun 的性能调优技巧。
Bun 为什么快
架构优势
┌─────────────────────────────────────────┐
│ Bun 架构 │
├─────────────────────────────────────────┤
│ Zig 语言编写的核心 │
│ JavaScriptCore 引擎 │
│ 优化的系统调用 │
│ 内置功能减少依赖 │
└─────────────────────────────────────────┘性能对比
| 操作 | Node.js | Bun | 提升 |
|---|---|---|---|
| 启动时间 | 40ms | 4ms | 10x |
| 包安装 | 30s | 1s | 30x |
| HTTP 请求/秒 | 50k | 150k | 3x |
| 文件读取 | 基准 | 3x faster | 3x |
HTTP 服务器优化
基本优化
typescript
const server = Bun.serve({
port: 3000,
// 使用简洁的响应
fetch(request) {
// ✅ 直接返回 Response
return new Response("Hello!");
// ❌ 避免不必要的异步
// return Promise.resolve(new Response("Hello!"));
},
});静态响应缓存
typescript
// 预创建常用响应
const notFoundResponse = new Response("Not Found", { status: 404 });
const okResponse = new Response("OK");
const jsonHeaders = { "Content-Type": "application/json" };
const server = Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/health") {
return okResponse; // 复用响应对象
}
if (url.pathname === "/api/data") {
// 预计算的 JSON
return new Response(cachedJsonString, { headers: jsonHeaders });
}
return notFoundResponse;
},
});流式响应
typescript
// 大数据使用流式响应
const server = Bun.serve({
port: 3000,
fetch(request) {
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 1000; i++) {
controller.enqueue(`data: ${i}\n`);
// 不阻塞其他请求
if (i % 100 === 0) {
await Bun.sleep(0);
}
}
controller.close();
},
});
return new Response(stream, {
headers: { "Content-Type": "text/event-stream" },
});
},
});文件 I/O 优化
使用 Bun.file()
typescript
// ✅ 使用 Bun.file(最快)
const content = await Bun.file("./data.txt").text();
// ❌ 避免 Node.js fs(较慢)
// import { readFile } from "fs/promises";
// const content = await readFile("./data.txt", "utf-8");批量文件操作
typescript
// ✅ 并行读取多个文件
const files = ["a.txt", "b.txt", "c.txt"];
const contents = await Promise.all(
files.map(f => Bun.file(f).text())
);
// ❌ 避免串行读取
// for (const f of files) {
// contents.push(await Bun.file(f).text());
// }流式写入大文件
typescript
// 大文件使用 writer
const writer = Bun.file("./large-output.txt").writer();
for (let i = 0; i < 1000000; i++) {
writer.write(`Line ${i}\n`);
// 定期刷新缓冲区
if (i % 10000 === 0) {
await writer.flush();
}
}
await writer.end();数据库优化
SQLite 优化
typescript
import { Database } from "bun:sqlite";
const db = new Database("app.db");
// 启用 WAL 模式
db.run("PRAGMA journal_mode = WAL");
db.run("PRAGMA synchronous = NORMAL");
db.run("PRAGMA cache_size = -64000"); // 64MB 缓存
db.run("PRAGMA temp_store = MEMORY");
// 使用预处理语句
const insert = db.prepare("INSERT INTO items (name) VALUES (?)");
const select = db.prepare("SELECT * FROM items WHERE id = ?");
// 批量插入使用事务
const insertMany = db.transaction((items: string[]) => {
for (const item of items) {
insert.run(item);
}
});连接池模式
typescript
// 为高并发场景创建多个连接
class DatabasePool {
private connections: Database[] = [];
private index = 0;
constructor(path: string, size: number = 4) {
for (let i = 0; i < size; i++) {
const db = new Database(path);
db.run("PRAGMA journal_mode = WAL");
this.connections.push(db);
}
}
get(): Database {
this.index = (this.index + 1) % this.connections.length;
return this.connections[this.index];
}
close() {
for (const conn of this.connections) {
conn.close();
}
}
}内存优化
减少内存分配
typescript
// ✅ 复用 Buffer
const buffer = new Uint8Array(1024);
function processData(data: Uint8Array) {
// 使用预分配的 buffer
buffer.set(data.slice(0, 1024));
return processBuffer(buffer);
}
// ❌ 避免频繁创建新对象
// function processData(data) {
// const buffer = new Uint8Array(1024); // 每次都分配
// ...
// }使用 --smol 模式
bash
# 减少内存使用(适合受限环境)
bun --smol app.ts监控内存使用
typescript
// 定期检查内存
setInterval(() => {
const usage = process.memoryUsage();
console.log({
heapUsed: `${(usage.heapUsed / 1024 / 1024).toFixed(2)} MB`,
heapTotal: `${(usage.heapTotal / 1024 / 1024).toFixed(2)} MB`,
external: `${(usage.external / 1024 / 1024).toFixed(2)} MB`,
});
}, 10000);并发优化
使用 Worker
typescript
// main.ts
const worker = new Worker("./worker.ts");
worker.postMessage({ type: "process", data: [1, 2, 3, 4, 5] });
worker.onmessage = (event) => {
console.log("结果:", event.data);
};
// worker.ts
self.onmessage = (event) => {
const { type, data } = event.data;
if (type === "process") {
const result = data.map((n: number) => n * 2);
self.postMessage(result);
}
};并行处理
typescript
// 使用 Promise.all 并行处理
async function processItems(items: string[]) {
const batchSize = 100;
const batches = [];
for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize));
}
const results = await Promise.all(
batches.map(batch => processBatch(batch))
);
return results.flat();
}构建优化
生产构建
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
// 生产优化
minify: true,
// Tree Shaking
treeshaking: true,
// 定义环境
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
},
});代码分割
typescript
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
splitting: true, // 自动代码分割
});网络优化
复用连接
typescript
// 复用 HTTP 连接
const agent = {
keepAlive: true,
keepAliveMsecs: 30000,
};
// Bun 默认复用连接,但可以配置压缩响应
typescript
const server = Bun.serve({
port: 3000,
async fetch(request) {
const data = JSON.stringify(largeData);
// 检查客户端是否支持压缩
const acceptEncoding = request.headers.get("accept-encoding") || "";
if (acceptEncoding.includes("gzip")) {
const compressed = Bun.gzipSync(data);
return new Response(compressed, {
headers: {
"Content-Type": "application/json",
"Content-Encoding": "gzip",
},
});
}
return Response.json(largeData);
},
});性能分析
内置分析
bash
# 查看详细的启动时间
bun --timing app.ts自定义计时
typescript
// 使用 console.time
console.time("operation");
await heavyOperation();
console.timeEnd("operation");
// 或使用 performance
const start = performance.now();
await heavyOperation();
const duration = performance.now() - start;
console.log(`耗时: ${duration.toFixed(2)}ms`);基准测试
typescript
// bench.ts
import { bench, run } from "bun:test";
bench("string concatenation", () => {
let s = "";
for (let i = 0; i < 1000; i++) {
s += "x";
}
});
bench("array join", () => {
const arr = [];
for (let i = 0; i < 1000; i++) {
arr.push("x");
}
arr.join("");
});
await run();运行:
bash
bun run bench.ts最佳实践清单
✅ 推荐做法
使用 Bun 原生 API
- Bun.file() 而非 fs
- Bun.serve() 而非 http
- bun:sqlite 而非第三方库
减少分配
- 复用对象和缓冲区
- 使用对象池
- 避免不必要的拷贝
批量处理
- 使用事务进行数据库操作
- 批量文件操作
- 减少 I/O 次数
并行处理
- Promise.all 并行请求
- Worker 处理 CPU 密集任务
- 流式处理大数据
合理配置
- 启用压缩
- 使用 WAL 模式
- 配置缓存
❌ 避免做法
- 频繁创建新对象
- 同步阻塞操作
- 忽略连接复用
- 未优化的数据库查询
- 不必要的数据复制
小结
本章介绍了:
- ✅ Bun 的性能优势
- ✅ HTTP 服务器优化
- ✅ 文件和数据库优化
- ✅ 内存和并发优化
- ✅ 构建和网络优化
- ✅ 性能分析工具
- ✅ 最佳实践清单
下一步
继续阅读 Node.js 兼容性 了解如何从 Node.js 迁移到 Bun。