实用 API
本教程共 34 篇 · 第 30 篇 · 更新于 2026-08-06
本节目标:
- 用
Bun.cron解析 cron 表达式、在进程内定时执行回调,或注册 OS 级定时任务。- 用
Bun.password完成密码的 argon2id/bcrypt 哈希与校验。- 区分
Bun.hash(非加密、快)与Bun.CryptoHasher(加密哈希、可增量)。- 用
Bun.gc/Bun.generateHeapSnapshot在性能调优时主动回收与抓取堆快照。- 认识
Bun.sleep、Bun.which、Bun.env、Bun.main等日常小工具。
这一章把 Bun 运行时里「不好归类但很常用」的工具 API 集中讲一遍。它们大多是同步或 Promise 化的小函数,能省掉引入额外 npm 包的麻烦。
30.1 Bun.cron:定时任务
Bun 内建了 cron 支持,提供三种能力:①解析表达式求下一次触发时间;②在当前进程内按调度执行回调;③注册 OS 级别的定时任务(重启后依然生效)。
// 1)进程内定时回调
Bun.cron("0 * * * *", async () => {
await cleanupTempFiles();
});
// 2)解析表达式,得到下一次触发的 Date
const next = Bun.cron.parse("30 9 * * MON-FRI");
// 3)注册 OS 级定时任务(脚本 + 表达式 + 任务名)
await Bun.cron("./worker.ts", "30 2 * * MON", "weekly-report");
Note版本落点要分清:OS 级注册与表达式解析在 v1.3.11 引入(2026-03-18 发布),进程内回调调度器在 v1.3.12 补齐(2026-04-09 发布)。到本教程基线版本 v1.3.14,两者都已可用。若你的环境停在 v1.3.11,
Bun.cron(expr, fn)这种写法还不存在。
表达式语法
标准 5 字段:分 时 日 月 周。字段支持 *、,(列表)、-(区间)、/(步长),月与星期可用英文缩写(JAN–DEC、MON–SUN,大小写不敏感,也接受全称),星期里 0 与 7 都表示周日。还支持预定义昵称:@yearly、@monthly、@weekly、@daily、@hourly。
Bun.cron.parse("*/15 * * * *"); // 下一个一刻钟整
Bun.cron.parse("@daily"); // 下一次午夜
Bun.cron.parse(expr, from?) 的第二个参数是搜索起点,省略则从当前时刻算起。返回最接近的 Date;如果约 4 年内都找不到匹配(例如写了 2 月 30 日这种永不成立的组合),返回 null。
还有一个 POSIX 兼容的细节值得记:当「日」和「周」两个字段同时被限定时,采用的是「或」逻辑——任一条件满足就触发,而不是两个都要满足。这一点经常被误解,写 0 0 13 * FRI 时以为只在「13 号且周五」跑,实际是「每月 13 号」加上「每个周五」都跑。
NoteOS 级任务在不同平台落到不同后端:Linux 写 crontab、macOS 用 launchd、Windows 用任务计划程序(schtasks)。日志位置也随之不同,Linux 查
journalctl,Windows 查事件查看器。
进程内回调 vs OS 级任务
两者语义不同,按需选择:
- 进程内回调(
Bun.cron(expr, fn)):随当前进程生命周期存在,进程退出任务即停;适合应用内周期任务,如清理缓存、轮询。它有几条明确保证:上一次回调结算完才排下一次(不会重叠执行)、按 UTC 调度、--hot重载前会先清理已注册任务、支持using自动释放。不希望它拖住进程退出,就调用job.unref()。 - OS 级任务(
Bun.cron(script, expr, name)):由系统调度器接管,机器重启后仍会运行;适合运维型定时脚本。用同一个任务名重复注册会原地覆盖旧任务,不再需要时用await Bun.cron.remove("weekly-report")卸载。
OS 级任务被触发时,Bun 会导入那个脚本并调用它默认导出的 scheduled() 方法,接口沿用了 Cloudflare Workers 的 Cron Triggers 约定:
// worker.ts
export default {
async scheduled(controller) {
// controller.cron 是触发它的那条表达式
// controller.scheduledTime 是计划触发的时间戳
await doWork();
},
};
所以「写个脚本 + 注册一次」就够了,不需要再额外常驻一个进程去等时间。
连续推算多次触发时间
parse() 可链式调用,把上一次结果当起点,得到接下来若干次触发时刻:
let cursor: Date | number = Date.now();
for (let i = 0; i < 3; i++) {
cursor = Bun.cron.parse("0 * * * *", cursor)!;
console.log(cursor.toISOString()); // 接下来三个整点
}
这在做「任务预览」类功能时很实用:用户填一条 cron 表达式,你当场把接下来五次执行时间列给他看,比让他自己解读表达式友好得多。
30.2 Bun.password:密码哈希与校验
Bun.password 专门处理密码这种「需要抗碰撞、抗暴力」的场景,默认算法是 argon2id,也支持 bcrypt。
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// $argon2id$v=19$m=65536,t=2,p=1$<salt>$<hash>
const isMatch = await Bun.password.verify(password, hash); // true
第二个参数可以选算法与调参:
const argon = await Bun.password.hash(password, {
algorithm: "argon2id", // "argon2id" | "argon2i" | "argon2d"
memoryCost: 8, // 内存成本(KiB,最小 8)
timeCost: 3, // 迭代次数
});
const bcrypt = await Bun.password.hash(password, {
algorithm: "bcrypt",
cost: 4, // 4–31
});
算法信息直接编码进哈希字符串里:bcrypt 用 Modular Crypt Format(MCF),argon2 用 PHC 格式。verify 会自动识别编码方式并选用对应校验逻辑。此外还有同步版本 Bun.password.hashSync / verifySync(计算量大,会阻塞线程,谨慎使用)。
这里有个新手常问的问题:盐值存哪儿? 答案是不用你操心。Bun.password.hash() 每次都会生成随机盐并写进返回的那串字符里,所以同一个密码两次哈希的结果一定不同。数据库里只存这一个字段就够了,不需要额外的 salt 列。
另一个容易搞错的是参数顺序:verify(明文, 哈希),别写反。写反了永远返回 false,还很难排查。
Tip示例里的
memoryCost: 8、cost: 4是为了让演示跑得快,不要照抄到生产。这两个参数越大越抗暴力破解,同时也越慢。合理做法是在目标机器上实测,把单次哈希耗时调到 100 毫秒上下。
Warning不要拿
Bun.hash(见下节)去哈希密码——它是非加密哈希,专为速度设计,不适合存储口令。密码场景一律用Bun.password。
30.3 Bun.hash 与 Bun.CryptoHasher:普通哈希
Bun.hash(非加密)
Bun.hash 用于哈希表、去重、校验和等追求速度的场合,默认用 Wyhash 生成 64 位哈希,返回 bigint。
Bun.hash("some data here"); // 11562320457524636935n
Bun.hash(new Uint8Array([1,2,3,4])); // 也支持 TypedArray / DataView / ArrayBuffer
Bun.hash("data", 1234); // 第二参数是可选 seed(64 位请用 BigInt)
还有一批命名算法可用(32 位返回 number,64 位返回 bigint):Bun.hash.crc32、adler32、cityHash32/64、xxHash32/64、xxHash3、murmur32v3/32v2/64v2、rapidhash、wyhash 等。
Bun.CryptoHasher(加密哈希,可增量)
需要 sha256/sha512/md5 等加密哈希、且数据要分块喂入时,用 Bun.CryptoHasher:
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.update(new Uint8Array([1, 2, 3]));
hasher.digest(); // Uint8Array(32)
支持的算法包括 blake2b256/512、blake2s256、sha1/224/256/384/512、sha512-224/256、sha3-224/256/384/512、shake128/256、ripemd160、md5、md4 等。传 key 还能算 HMAC:new Bun.CryptoHasher("sha256", "secret-key")。
Tip需要 Node 兼容接口时,
node:crypto的createHash/createHmac在 Bun 下也可用;Bun.CryptoHasher是 Bun 原生、更贴近增量的写法。
30.4 Bun.gc 与 Bun.generateHeapSnapshot:内存排查
JS 是垃圾回收语言,对象通常不是立即释放。做性能调优或排查内存泄漏时,可手动触发 GC 或抓取堆快照。
Bun.gc(true); // 同步执行一次垃圾回收
Bun.gc(false); // 异步执行
抓堆快照(可用 Safari / WebKit GTK 开发者工具打开分析):
import { generateHeapSnapshot } from "bun";
const snapshot = generateHeapSnapshot();
await Bun.write("heap.json", JSON.stringify(snapshot, null, 2));
Note这两个 API 主要服务于调试与基准测试(见第 33 章),常规业务代码无需调用
Bun.gc。Bun.generateHeapSnapshot来自内置的bun模块。
30.5 日常小工具
| API | 作用 |
|---|---|
Bun.sleep(ms) / Bun.sleepSync(ms) | 等待若干毫秒(后者阻塞线程);也可传 Date 等待到指定时刻 |
Bun.which(bin, opts?) | 类似终端 which,按 PATH 查找可执行文件路径,替代 which 包 |
Bun.env | process.env 的别名 |
Bun.main | 当前程序入口文件的绝对路径,用于判断脚本是被直接运行还是被导入 |
Bun.version / Bun.revision | 当前 bun CLI 的版本号 / 编译所用的 git commit |
Bun.randomUUIDv7() | 生成 UUID v7(按时间排序) |
判断脚本是否「被直接运行」的常见写法:
if (import.meta.path === Bun.main) {
// 直接 `bun run` 执行的入口逻辑
} else {
// 被别的模块 import
}
几个小工具的实际用法:
console.log(Bun.version); // "1.3.14"
await Bun.sleep(1000); // 等 1 秒
await Bun.sleep(new Date(Date.now() + 5000)); // 等到 5 秒后的时刻
const ls = Bun.which("ls"); // "/usr/bin/ls"(按 PATH 查找)
const custom = Bun.which("node", { PATH: "/opt/bin:/usr/bin" });
const id = Bun.randomUUIDv7(); // 时间有序的 UUID v7
Bun.which 本质上是跨平台版的系统 which,能少装一个 which npm 包;Bun.sleep 既能收毫秒也能收 Date,比手写 setTimeout 包裹的 Promise 更直观。
30.6 小结
Bun.cron:解析表达式 + 进程内回调 + OS 级任务,三合一。Bun.password:密码专用,默认 argon2id,自动识别编码、自带盐值。Bun.hash:非加密、快;Bun.CryptoHasher:加密、可增量。密码别用前者。Bun.gc/Bun.generateHeapSnapshot:调试与性能调优专用。Bun.sleep/Bun.which/Bun.main等小工具,能少装几个 npm 包就少装。
Tip这些 API 都属于「运行时内置」,无需任何依赖。用到哪个就直接
import或访问全局Bun命名空间即可;想看完整清单可回顾第 31 章所涉及的生态与官方 API 总览。
30.7 与 Node.js 兼容层的对应
为了方便迁移现有代码,Bun 也兼容一部分 Node.js 的同名 API,可作为备选:
- 加密哈希:
node:crypto的createHash/createHmac在 Bun 下可用,等价于Bun.CryptoHasher的用途。 - 密码学随机:
node:crypto的randomUUID/randomBytes同样可用,Bun额外提供了按时间排序的Bun.randomUUIDv7()。 - 子进程:
node:child_process的spawn/execFile在 Bun 下能跑,但Bun.spawn的流模型和Bun.$的 Shell 语法通常更顺手。
Note兼容性不是「照搬 Node」——Bun 在大多数场景行为一致,但个别边缘行为可能有差异。生产迁移前建议对关键路径补测试(参见第 21–25 章的测试章节)。