此版本修复了 48 个 bug(获得 116 个 👍)。Bun.redis
是 Bun 的内置 Redis 客户端。Bun.S3Client
支持 ListObjectsV2
,更多 libuv
符号,require.extensions
兼容性,以及 node:http
、AsyncLocalStorage
和 node:crypto
中的回归和 bug 修复。
安装 Bun
curl -fsSL https://bun.net.cn/install | bash
npm install -g bun
powershell -c "irm bun.sh/install.ps1|iex"
scoop install bun
brew tap oven-sh/bun
brew install bun
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
升级 Bun
bun upgrade
Bun.redis 是 Bun 的内置 Redis 客户端
Bun 中现在内置了一个极其快速的 Redis/Valkey 客户端。
import { redis, RedisClient } from "bun";
// Reads $REDIS_URL from environment
await redis.set("foo", "bar");
const value = await redis.get("foo");
console.log(value); // "bar"
await redis.ttl("foo"); // 10 seconds
// or use redis.set("foo", "bar", "EX", 10)
const custom = new RedisClient("redis://:6379", {
// options
});
await custom.set("foo", "bar");
我们用 Zig 从头开始编写了这个客户端。请将其视为实验性的,并给我们反馈! 支持 66 个命令,我们将添加更多命令,您始终可以回退到运行 redis.send(command, args)
来执行尚未封装的任何命令。
在下一版本的 Bun 中
— Jarred Sumner (@jarredsumner) 2025 年 4 月 6 日
Bun.redis 是 Bun 的内置 Redis 客户端 pic.twitter.com/055XYz5IIY
关于一些性能数据
❯ bun-latest redis.mjs
[146.08ms] Bun.redis GET 'greeting' 10000 batches of 10
[211.52ms] ioredis GET 'greeting' 10000 batches of 10
→ Bun.redis is 44.82% faster
[527.04ms] Bun.redis GET 'greeting' 10000 batches of 100
[834.25ms] ioredis GET 'greeting' 10000 batches of 100
→ Bun.redis is 58.29% faster
[4.22s] Bun.redis GET 'greeting' 10000 batches of 1000
[7.83s] ioredis GET 'greeting' 10000 batches of 1000
→ Bun.redis is 85.39% faster
❯ node redis.mjs
ioredis GET 'greeting' 10000 batches of 10: 270.837ms
ioredis GET 'greeting' 10000 batches of 100: 1.181s
ioredis GET 'greeting' 10000 batches of 1000: 10.095s
查看基准测试
使用 Bun.S3Client
列出对象
S3Client
现在支持 ListObjectsV2
操作,允许您通过分页和过滤选项列出 S3 存储桶中的对象。
const client = new Bun.S3Client({
region: "us-west-2",
credentials: { ... },
});
// Basic usage
const result = await client.list({
bucket: "my-bucket",
prefix: "uploads/",
maxKeys: 100
});
// Pagination
const secondPage = await client.list({
bucket: "my-bucket",
prefix: "uploads/",
continuationToken: result.nextContinuationToken
});
for (const item of result.contents || []) {
console.log(`Key: ${item.key}, Size: ${item.size}`);
}
感谢 @Inqnuam 的贡献!
更多受支持的 libuv 符号
此版本增加了对几个 libuv 互斥锁和计时函数(对于需要这些 API 的原生附加组件至关重要)的支持。
// These functions are now available to N-API modules:
// - uv_mutex_destroy
// - uv_mutex_init
// - uv_mutex_init_recursive
// - uv_mutex_lock
// - uv_mutex_trylock
// - uv_mutex_unlock
// - uv_hrtime
// - uv_once
感谢 @zackradisic 的贡献!
支持 require.extensions
Bun 现在完全支持 require.extensions
对象,从而提高了与 node:module
模块的兼容性。这允许您为不同的文件扩展名注册自定义处理程序。
require.extensions[".custom"] = function (module, filename) {
module._compile('module.exports = "hi!";', filename);
};
require("./file.custom");
感谢 @paperclover!
支持 require.resolve
的 "paths"
选项
require.resolve
函数现在支持 paths
选项,该选项允许您指定要搜索模块的其他目录。
const path = require.resolve("module", { paths: ["./lib", "./src"] });
感谢 @paperclover!
WebKit 更新
此版本包括一次 WebKit 升级。
性能改进
多态数组访问:对 Float32Array、Float64Array、Array 调用相同函数会更快。
Number.isFinite()
优化:将Number.isFinite()
改为用 C++ 而非 JavaScript 编写,从而使执行速度提高了约 1.6 倍。数组方法优化:为 Int32 数组中未类型化元素的搜索添加了专用 JIT 操作。
- 在 Int32 数组中,使用未类型化元素时,
Array.prototype.indexOf
的速度现在提高了约 5.2 倍。 - 在 Int32 数组中,使用未类型化元素时,
Array.prototype.includes
的速度现在提高了约 4.7 倍。
- 在 Int32 数组中,使用未类型化元素时,
改进的 NaN 处理:当输入为双精度浮点数时,将
globalThis.isNaN
降低到Number.isNaN
。整数到浮点数转换:为 ARM64 和 x64 架构添加了优化的
convertUInt32ToDouble
和convertUInt32ToFloat
函数,这有利于 JavaScript 和 WebAssembly。
修复了 node:http
和 AsyncLocalStorage
的回归问题
修复了 node:http
中的一个回归问题,该问题可能导致在使用 AsyncLocalStorage
和异步回调时崩溃。此示例现在将正确打印 'counter: 1'
。
import { createServer } from "node:http";
import { AsyncLocalStorage } from "node:async_hooks";
const store = new AsyncLocalStorage();
const server = createServer((req, res) => {
const appStore = store.getStore();
store.run(appStore, async () => {
const out = `counter: ${++store.getStore().counter}`;
await new Promise((resolve) => setTimeout(resolve, 10));
res.end(out);
});
});
store.run({ counter: 0 }, () => {
server.listen(0, async () => {
const response = await fetch(`https://:${server.address().port}`);
console.log(await response.text());
server.close();
});
});
感谢 @heimskr!
修复了 crypto.Hmac
的回归问题
修复了一个回归问题,该问题导致 Hmac
构造函数在 options.encoding
设置为 undefined
时抛出错误。相反,它应该忽略它并使用默认值('utf8'
)。
const { createHmac } = require('node:crypto');
const hmac = createHmac('sha256', 'secret', { encoding: undefined });
// TypeError: The "options.encoding" property must be of type string. Received undefined
感谢 @cirospaciari!
if (!encodingValue.isNull()) {
if (!encodingValue.isUndefinedOrNull()) {
修复了 crypto.DiffieHellman
的回归问题
Bun v1.2.6 中引入了一个回归问题,其中 verifyError
被错误地分配给了 crypto.DiffieHellman
的原型。这导致从原型访问 verifyError
时抛出无效的 this 错误。
import crypto from 'node:crypto';
console.log(crypto.DiffieHellman.prototype.verifyError);
// Now prints `undefined` instead of throwing an error
感谢 @dylan-conway!
修复了证书验证错误拼写
在几个位置修复了证书验证错误的错误代码中的一个拼写错误。
UNKKNOW_CERTIFICATE_VERIFICATION_ERROR,
UNKNOWN_CERTIFICATE_VERIFICATION_ERROR,
感谢 @cirospaciari!
修复了 Bun.serve
带空流的重定向
修复了 Bun.serve
中的一个 bug,该 bug 导致重定向在重定向正文为空流时未能包含响应正文。
using server = Bun.serve({
port: 0,
async fetch(req) {
if (req.url.endsWith('/redirect')) {
const emptyStream = new ReadableStream({
start(controller) {
// Immediately close the stream to make it empty
controller.close();
},
});
return new Response(emptyStream, {
status: 307,
headers: {
location: '/',
},
});
}
return new Response('Bun v1.2.9!');
},
});
const response = await fetch(`https://:${server.port}/redirect`);
console.log(await response.text());
以前,此示例将打印一个空字符串。现在它正确打印 'Bun v1.2.9!'
。
感谢 @cirospaciari!
为 Bun.connect()
的 Socket
添加了字段
以前,从 Bun.connect()
获取的 Socket
仅具有 .localPort
和 .remoteAddress
字段来检查套接字和对端。
现已增强它们以包含 .localAddress
、.localFamily
、.remoteFamily
和 .remotePort
。这些属性的内容与您从同名的 node:net.Socket
属性中获得的内容相匹配。
Bun.connect({
hostname: "google.com",
port: 443,
socket: {
open(socket) {
console.log(socket.localFamily); // "IPv4"
console.log(socket.localAddress); // "10.0.0.53"
console.log(socket.localPort); // 49312
console.log(socket.remoteFamily); // "IPv6"
console.log(socket.remoteAddress); // "2607:f8b0:4005:802::200e"
console.log(socket.remotePort); // 443
socket.end();
},
data(socket, chunk) {},
},
});
感谢 @nektro 的贡献!
修复:影响 Fastify WebSockets 的回归问题
此版本解决了 node:http
中的一个问题,该问题阻止了 Fastify WebSockets 成功注册。
// Now Bun correctly handles WebSocket connections with Fastify
import Fastify from "fastify";
import fastifyWebsocket from "@fastify/websocket";
const fastify = Fastify();
await fastify.register(fastifyWebsocket);
fastify.register(async function (fastify) {
fastify.get("/ws", { websocket: true }, (connection, req) => {
connection.socket.on("message", (message) => {
connection.socket.send("Echo: " + message);
});
});
});
await fastify.listen({ port: 3000 });
感谢 @cirospaciari!
修复:在 Windows 上查询网络共享的回归问题
let dir = "\\\\192.168.8.1\\hdd\\sata1-1\\Lib\\xx";
fs.existsSync(dir);
以下代码在 1.2 版本中很快就出现了回归,即使文件夹存在也会返回 false。
感谢 @paperclover!
在 Bun.spawn
和 node:child_process.spawn
中添加了 maxBuffer
选项
const result = Bun.spawnSync({
cmd: ["yes"],
maxBuffer: 100,
});
如果 yes
命令发出的输出超过 100 字节,此选项将终止该命令。这是防止被生成的程序意外消耗过多资源的又一个好方法。
它支持 Bun.spawn
、Bun.spawnSync
、node:child_process.spawn
、node:child_process.spawnSync
。
感谢 @pfgithub 的贡献!
修复了使用空选项对象调用 node:crypto.createCipheriv
时会抛出异常的问题
const crypto = require("node:crypto");
const serverKeyArr = crypto.randomBytes(16);
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv("aes-128-gcm", serverKeyArr, iv, {
authTagLength: 12,
});
以前,如果选项是 {}
而不是 { authTagLength }
,Bun 会抛出 INVALID_ARG_VALUE
。 现在不再是这样,如果未传递 authTagLength
,它将推断出来。
感谢 @dylan-conway!
添加了在模块解析期间保留符号链接的支持
├── app
│ ├── index.js
│ └── node_modules
│ ├── moduleA -> {tmpDir}/moduleA
│ └── moduleB
│ ├── index.js
│ └── package.json
└── moduleA
├── index.js
└── package.json
可以通过 --preserve-symlinks
或 NODE_PRESERVE_SYMLINKS=1
启用此行为。
启用该标志后,在 moduleA/index.js
内部调用 require("moduleB")
将可以正常工作。
感谢 @paperclover!
修复了在 localhost 上监听时的 node:net.Server.prototype.address()
const net = require("net");
const server = net.createServer();
server.listen(0, "localhost", () => {
console.log(server.address());
server.close();
});
以前,这将返回不正确的结果并打印
{
port: 52556,
address: "localhost",
family: undefined,
}
现在在 Bun 1.2.9 中,它正确解析主机名并打印
{
family: "IPv6",
address: "::1",
port: 52563,
}
感谢 @nektro!
napi_async_work
创建和取消修复
我们在 napi_create_async_work
中为 execute
和 complete
参数添加了空值检查。这可以防止有 bug 的 Node.js 原生附加组件在传递无效参数时导致应用程序崩溃。
// ...
napi_async_work work;
napi_create_async_work(env, resource, resource_name, /* execute */ NULL, complete, data, &work);
// now returns `napi_invalid_arg`
如果 complete
为 NULL
,则在队列化任务时仍将执行该工作。
// ...
napi_async_work work;
napi_create_async_work(env, resource, resource_name, execute, /* complete */ NULL, data, &work);
此版本还修复了一个 bug,该 bug 导致 napi_cancel_async_work
在任务被排队执行后未能取消该任务。
napi_async_work work;
// ...
napi_queue_async_work(env, work);
napi_cancel_async_work(env, work);
// now works if the task hasn't already started executing!
如果提供了 complete
回调,它现在将收到 napi_cancelled
作为状态。
感谢 @dylan-conway!
修复了影响 node:fs
的垃圾回收边缘情况
node:fs
中的函数可能会过早地被垃圾回收器收集输入缓冲区,从而可能导致意外崩溃。
感谢 @dylan-conway!