執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

工具函式

使用 Bun 的實用函式操作執行環境

Bun.version

包含當前正在執行的 bun CLI 版本的字串。

terminal
Bun.version;
// => "1.3.3"

Bun.revision

用於建置當前 bun CLI 的 Bun 的 git 提交雜湊值。

terminal
Bun.revision;
// => "f02561530fda1ee9396f51c8bc99b38716e38296"

Bun.env

process.env 的別名。

Bun.main

當前程式入口點的絕對路徑(即你通過 bun run 執行的檔案)。

script.ts
Bun.main;
// /path/to/script.ts

使用此屬性可確定指令碼是直接執行,還是由另一個指令碼匯入。

TypeScript
if (import.meta.path === Bun.main) {
  // 這個指令碼被直接執行
} else {
  // 這個檔案被其他指令碼匯入
}

此檢查類似於 Node.js 中的 require.main = module 技巧。

Bun.sleep()

Bun.sleep(ms: number)

傳回一個在指定毫秒後完成的 Promise。

TypeScript
console.log("hello");
await Bun.sleep(1000);
console.log("hello one second later!");

或者,傳入一個 Date 物件,傳回在該時間點完成的 Promise。

TypeScript
const oneSecondInFuture = new Date(Date.now() + 1000);

console.log("hello");
await Bun.sleep(oneSecondInFuture);
console.log("hello one second later!");

Bun.sleepSync()

Bun.sleepSync(ms: number)

同步阻塞版本的 Bun.sleep。

TypeScript
console.log("hello");
Bun.sleepSync(1000); // 阻塞執行緒一秒鐘
console.log("hello one second later!");

Bun.which()

Bun.which(bin: string)

傳回執行檔的路徑,類似於終端中輸入 which。

TypeScript
const ls = Bun.which("ls");
console.log(ls); // "/usr/bin/ls"

預設情況下,Bun 會檢視當前的 PATH 環境變數。要自定義 PATH:

TypeScript
const ls = Bun.which("ls", {
  PATH: "/usr/local/bin:/usr/bin:/bin",
});
console.log(ls); // "/usr/bin/ls"

傳入 cwd 選項,可從特定目錄中解析執行檔。

TypeScript
const ls = Bun.which("ls", {
  cwd: "/tmp",
  PATH: "",
});

console.log(ls); // null

這是 which npm 包的內建替代方案。

Bun.randomUUIDv7()

Bun.randomUUIDv7() 生成一個 UUID v7,它具有單調性,適合排序和資料庫使用。

TypeScript
import { randomUUIDv7 } from "bun";

const id = randomUUIDv7();
// => "0192ce11-26d5-7dc3-9305-1426de888c5a"

UUID v7 是一種 128 位值,其中編碼了當前時間戳、一個隨機值和一個計數器。時間戳使用最高有效的 48 位進行編碼,隨機值和計數器則使用剩餘位進行編碼。

timestamp 引數預設為當前時間(以毫秒為單位)。當時鍾前進時,Bun 會將計數器重新設定為一個新的偽隨機整數。Bun 在重新設定計數器時會將其 12 位中的最高位清零,因此在迴繞之前至少還剩 2048 個值。如果時鐘尚未前進到超過上次發出的時間戳,Bun 會重用上次發出的時間戳並遞增計數器。如果計數器迴繞,Bun 會將發出的時間戳向前推進,而不是讓計數器迴繞,因此傳回的 UUID 會保持嚴格遞增(RFC 9562 §6.2)。計數器是原子操作且執行緒安全的,因此同一行程中多個 Worker 在同一時間戳下呼叫 Bun.randomUUIDv7() 時,不會產生衝突的計數器值。

傳入顯式的 timestamp 時,Bun 會原樣編碼該值,併為其跟蹤單獨的計數器,因此顯式時間戳呼叫不會觀察或更改預設路徑使用的單調狀態。使用相同的顯式時間戳重複呼叫時,會遞增該獨立計數器;計數器迴繞時,也會向前推進發出的時間戳,因此生成的 UUID 始終可排序。使用不同的顯式時間戳呼叫時,會重新設定該計數器。

UUID 的最後 8 個位元組(除兩個變體位外)是一個密碼學安全的隨機值。Bun.randomUUIDv7() 使用與 crypto.randomUUID() 相同的隨機數生成器。該生成器來自 BoringSSL。BoringSSL 的隨機性則來自平臺專用的系統隨機數生成器,而底層硬體通常會提供該生成器。

TypeScript
namespace Bun {
  function randomUUIDv7(encoding?: "hex" | "base64" | "base64url" = "hex", timestamp?: number = Date.now()): string;
  /**
   * 傳入 "buffer" 時,傳回 16 位元組的 Buffer 而非字串。
   */
  function randomUUIDv7(encoding: "buffer", timestamp?: number = Date.now()): Buffer;

  // 只傳時間戳引數時傳回十六進位制字串
  function randomUUIDv7(timestamp?: number = Date.now()): string;
}

將 "buffer" 作為編碼傳入,即可獲取一個 16 位元組的緩衝區,而不是字串。這樣可以避免字串轉換開銷。

buffer.ts
const buffer = Bun.randomUUIDv7("buffer");

還支援 base64 和 base64url 編碼,以獲得更短的字串。

base64.ts
const base64 = Bun.randomUUIDv7("base64");
const base64url = Bun.randomUUIDv7("base64url");

Bun.peek()

Bun.peek(prom: Promise)

讀取 Promise 的結果而無須 await 或 .then,前提是 Promise 已經完成或拒絕。

TypeScript
import { peek } from "bun";

const promise = Promise.resolve("hi");

// 不用 await!
const result = peek(promise);
console.log(result); // "hi"

在對效能敏感的程式碼中使用它來避免多餘的微任務。這是一個高階 API;在生產環境中使用前,請先檢視以下範例。

TypeScript
import { peek } from "bun";
import { expect, test } from "bun:test";

test("peek", () => {
  const promise = Promise.resolve(true);

  // 不用 await
  expect(peek(promise)).toBe(true);

  // 再次 peek 傳回相同值
  const again = peek(promise);
  expect(again).toBe(true);

  // peek 非 Promise 型別傳回原值
  const value = peek(42);
  expect(value).toBe(42);

  // peek 一個掛起的 Promise 傳回該 Promise
  const pending = new Promise(() => {});
  expect(peek(pending)).toBe(pending);

  // peek 拒絕的 Promise:
  // - 傳回錯誤物件
  // - 不標記 Promise 已處理
  const rejected = Promise.reject(new Error("Successfully tested promise rejection"));
  expect(peek(rejected).message).toBe("Successfully tested promise rejection");
});

peek.status 讀取 Promise 的狀態,而不會解析它。

TypeScript
import { peek } from "bun";
import { expect, test } from "bun:test";

test("peek.status", () => {
  const promise = Promise.resolve(true);
  expect(peek.status(promise)).toBe("fulfilled");

  const pending = new Promise(() => {});
  expect(peek.status(pending)).toBe("pending");

  const rejected = Promise.reject(new Error("oh nooo"));
  expect(peek.status(rejected)).toBe("rejected");
});

Bun.openInEditor()

在預設編輯器中開啟檔案。Bun 會根據 $VISUAL 或 $EDITOR 環境變數自動檢測編輯器。

TypeScript
const currentFile = import.meta.url;
Bun.openInEditor(currentFile);

你可以通過 bunfig.toml 中的 debug.editor 設定覆蓋此行為。

bunfig.toml
[debug] # [!code ++]
editor = "code" # [!code ++]

或者通過 editor 引數指定編輯器,並指定行列號。

TypeScript
Bun.openInEditor(import.meta.url, {
  editor: "vscode", // 或 "subl"
  line: 10,
  column: 5,
});

Bun.deepEquals()

遞迴檢查兩個物件是否等價。bun:test 中的 expect().toEqual() 內部使用了這個方法。

TypeScript
const foo = { a: 1, b: 2, c: { d: 3 } };

// true
Bun.deepEquals(foo, { a: 1, b: 2, c: { d: 3 } });

// false
Bun.deepEquals(foo, { a: 1, b: 2, c: { d: 4 } });

傳入第三個布林引數以啟用“嚴格”模式。測試執行器中的 expect().toStrictEqual() 使用這個模式。

TypeScript
const a = { entries: [1, 2] };
const b = { entries: [1, 2], extra: undefined };

Bun.deepEquals(a, b); // => true
Bun.deepEquals(a, b, true); // => false

在嚴格模式下,Bun 會將以下情況視為不相等:

TypeScript
// undefined 值
Bun.deepEquals({}, { a: undefined }, true); // false

// 陣列中的 undefined
Bun.deepEquals(["asdf"], ["asdf", undefined], true); // false

// 稀疏陣列
Bun.deepEquals([, 1], [undefined, 1], true); // false

// 物件字面量與類例項(即使屬性相同)
class Foo {
  a = 1;
}
Bun.deepEquals(new Foo(), { a: 1 }, true); // false

Bun.escapeHTML()

Bun.escapeHTML(value: string | object | number | boolean): string

轉義輸入字串中的以下字元:

  • " 轉為 "
  • & 轉為 &
  • ' 轉為 '
  • < 轉為 &lt;
  • > 轉為 &gt;

此函式針對大型輸入進行了最佳化。在 M1 Max 上,其處理速度為 480 MB/s 至 20 GB/s,具體取決於要轉義的資料量以及是否包含非 ASCII 文本。Bun 會先將非字串型別轉換為字串,再進行轉義。

Bun.stringWidth()

獲取字串在終端中顯示時所佔的列數。支援 ANSI 轉義碼、表情符號和寬字元。

範例:

TypeScript
Bun.stringWidth("hello"); // => 5
Bun.stringWidth("\u001b[31mhello\u001b[0m"); // => 5
Bun.stringWidth("\u001b[31mhello\u001b[0m", { countAnsiEscapeCodes: true }); // => 12

用於在終端中對齊文本,或檢查字串是否包含 ANSI 轉義碼。

此 API 與 "string-width" npm 包相同,因此你可以將現有程式碼移植到 Bun,反之亦然。

在此基準測試中,對於長度大於約 500 個字元的輸入,Bun.stringWidth 比 string-width npm 包快約 6,756 倍。非常感謝 sindresorhus 在 string-width 方面所做的工作。

TypeScript
❯ bun string-width.mjs
cpu: 13th Gen Intel(R) Core(TM) i9-13900
runtime: bun 1.0.29 (x64-linux)

benchmark                                          time (avg)             (min … max)       p75       p99      p995
------------------------------------------------------------------------------------- -----------------------------
Bun.stringWidth     500 chars ascii              37.09 ns/iter   (36.77 ns … 41.11 ns)  37.07 ns  38.84 ns  38.99 ns

❯ node string-width.mjs

benchmark                                          time (avg)             (min … max)       p75       p99      p995
------------------------------------------------------------------------------------- -----------------------------
npm/string-width    500 chars ascii             249,710 ns/iter (239,970 ns … 293,180 ns) 250,930 ns  276,700 ns 281,450 ns

Bun.stringWidth 使用原生程式碼和 SIMD 指令實現,並支援 Latin1、UTF-16 和 UTF-8 編碼。它通過了 string-width 的測試。

檢視完整基準測試

1 納秒(ns)是十億分之一秒。單位換算如下:

單位1 毫秒等於
ns1,000,000
µs1,000
ms1
terminal
❯ bun string-width.mjs
cpu: 13th Gen Intel(R) Core(TM) i9-13900
runtime: bun 1.0.29 (x64-linux)

benchmark                                          time (avg)             (min … max)       p75       p99      p995
------------------------------------------------------------------------------------- -----------------------------
Bun.stringWidth      5 chars ascii              16.45 ns/iter   (16.27 ns … 19.71 ns)  16.48 ns  16.93 ns  17.21 ns
Bun.stringWidth     50 chars ascii              19.42 ns/iter   (18.61 ns … 27.85 ns)  19.35 ns   21.7 ns  22.31 ns
Bun.stringWidth    500 chars ascii              37.09 ns/iter   (36.77 ns … 41.11 ns)  37.07 ns  38.84 ns  38.99 ns
Bun.stringWidth  5,000 chars ascii              216.9 ns/iter  (215.8 ns … 228.54 ns) 216.23 ns 228.52 ns 228.53 ns
Bun.stringWidth 25,000 chars ascii               1.01 µs/iter     (1.01 µs … 1.01 µs)   1.01 µs   1.01 µs   1.01 µs
Bun.stringWidth      7 chars ascii+emoji         54.2 ns/iter   (53.36 ns … 58.19 ns)  54.23 ns  57.55 ns  57.94 ns
Bun.stringWidth     70 chars ascii+emoji       354.26 ns/iter (350.51 ns … 363.96 ns) 355.93 ns 363.11 ns 363.96 ns
Bun.stringWidth    700 chars ascii+emoji          3.3 µs/iter      (3.27 µs … 3.4 µs)    3.3 µs    3.4 µs    3.4 µs
Bun.stringWidth  7,000 chars ascii+emoji        32.69 µs/iter   (32.22 µs … 45.27 µs)   32.7 µs  34.57 µs  34.68 µs
Bun.stringWidth 35,000 chars ascii+emoji       163.35 µs/iter (161.17 µs … 170.79 µs) 163.82 µs 169.66 µs 169.93 µs
Bun.stringWidth      8 chars ansi+emoji         66.15 ns/iter   (65.17 ns … 69.97 ns)  66.12 ns   69.8 ns  69.87 ns
Bun.stringWidth     80 chars ansi+emoji        492.95 ns/iter  (488.05 ns … 499.5 ns)  494.8 ns 498.58 ns  499.5 ns
Bun.stringWidth    800 chars ansi+emoji          4.73 µs/iter     (4.71 µs … 4.88 µs)   4.72 µs   4.88 µs   4.88 µs
Bun.stringWidth  8,000 chars ansi+emoji         47.02 µs/iter   (46.37 µs … 67.44 µs)  46.96 µs  49.57 µs  49.63 µs
Bun.stringWidth 40,000 chars ansi+emoji        234.45 µs/iter (231.78 µs … 240.98 µs) 234.92 µs 236.34 µs 236.62 µs
Bun.stringWidth     19 chars ansi+emoji+ascii  135.46 ns/iter (133.67 ns … 143.26 ns) 135.32 ns 142.55 ns 142.77 ns
Bun.stringWidth    190 chars ansi+emoji+ascii    1.17 µs/iter     (1.16 µs … 1.17 µs)   1.17 µs   1.17 µs   1.17 µs
Bun.stringWidth  1,900 chars ansi+emoji+ascii   11.45 µs/iter   (11.26 µs … 20.41 µs)  11.45 µs  12.08 µs  12.11 µs
Bun.stringWidth 19,000 chars ansi+emoji+ascii  114.06 µs/iter (112.86 µs … 120.06 µs) 114.25 µs 115.86 µs 116.15 µs
Bun.stringWidth 95,000 chars ansi+emoji+ascii  572.69 µs/iter (565.52 µs … 607.22 µs) 572.45 µs 604.86 µs 605.21 µs
terminal
❯ node string-width.mjs
cpu: 13th Gen Intel(R) Core(TM) i9-13900
runtime: node v21.4.0 (x64-linux)

benchmark                                           time (avg)             (min … max)       p75       p99      p995
-------------------------------------------------------------------------------------- -----------------------------
npm/string-width      5 chars ascii               3.19 µs/iter     (3.13 µs … 3.48 µs)   3.25 µs   3.48 µs   3.48 µs
npm/string-width     50 chars ascii              20.09 µs/iter  (18.93 µs … 435.06 µs)  19.49 µs  21.89 µs  22.59 µs
npm/string-width    500 chars ascii             249.71 µs/iter (239.97 µs … 293.18 µs) 250.93 µs  276.7 µs 281.45 µs
npm/string-width  5,000 chars ascii               6.69 ms/iter     (6.58 ms … 6.76 ms)   6.72 ms   6.76 ms   6.76 ms
npm/string-width 25,000 chars ascii             139.57 ms/iter (137.17 ms … 143.28 ms) 140.49 ms 143.28 ms 143.28 ms
npm/string-width      7 chars ascii+emoji          3.7 µs/iter     (3.62 µs … 3.94 µs)   3.73 µs   3.94 µs   3.94 µs
npm/string-width     70 chars ascii+emoji        23.93 µs/iter   (22.44 µs … 331.2 µs)  23.15 µs  25.98 µs   30.2 µs
npm/string-width    700 chars ascii+emoji       251.65 µs/iter (237.78 µs … 444.69 µs) 252.92 µs 325.89 µs 354.08 µs
npm/string-width    7,000 chars ascii+emoji         4.95 ms/iter     (4.82 ms … 5.19 ms)      5 ms   5.04 ms   5.19 ms
npm/string-width 35,000 chars ascii+emoji        96.93 ms/iter  (94.39 ms … 102.58 ms)  97.68 ms 102.58 ms 102.58 ms
npm/string-width      8 chars ansi+emoji          3.92 µs/iter     (3.45 µs … 4.57 µs)   4.09 µs   4.57 µs   4.57 µs
npm/string-width     80 chars ansi+emoji         24.46 µs/iter     (22.87 µs … 4.2 ms)  23.54 µs  25.89 µs  27.41 µs
npm/string-width    800 chars ansi+emoji        259.62 µs/iter (246.76 µs … 480.12 µs) 258.65 µs 349.84 µs 372.55 µs
npm/string-width  8,000 chars ansi+emoji          5.46 ms/iter     (5.41 ms … 5.57 ms)   5.48 ms   5.55 ms   5.57 ms
npm/string-width 40,000 chars ansi+emoji        108.91 ms/iter (107.55 ms … 109.5 ms) 109.25 ms  109.5 ms  109.5 ms
npm/string-width     19 chars ansi+emoji+ascii    6.53 µs/iter     (6.35 µs … 6.75 µs)   6.54 µs   6.75 µs   6.75 µs
npm/string-width    190 chars ansi+emoji+ascii   55.52 µs/iter (52.59 µs … 352.73 µs)  54.19 µs  80.77 µs 167.21 µs
npm/string-width  1,900 chars ansi+emoji+ascii  701.71 µs/iter (653.94 µs … 893.78 µs)  715.3 µs 855.37 µs  872.9 µs
npm/string-width 19,000 chars ansi+emoji+ascii   27.19 ms/iter   (26.89 ms … 27.41 ms)  27.28 ms  27.41 ms  27.41 ms
npm/string-width 95,000 chars ansi+emoji+ascii     3.68 s/iter        (3.66 s … 3.7 s)    3.69 s     3.7 s     3.7 s

TypeScript 定義:

expandable
namespace Bun {
  export function stringWidth(
    /**
     * 要測量的字串
     */
    input: string,
    options?: {
      /**
       * 為 `true` 時,計算 ANSI 轉義碼為字串寬度一部分。為 `false` 時忽略 ANSI 轉義碼。
       *
       * @default false
       */
      countAnsiEscapeCodes?: boolean;
      /**
       * 模糊情況下,為 `true` 時表情符號寬度算作 1,`false` 視作 2。
       *
       * @default true
       */
      ambiguousIsNarrow?: boolean;
    },
  ): number;
}

Bun.fileURLToPath()

將 file:// URL 轉換成絕對路徑。

TypeScript
const path = Bun.fileURLToPath(new URL("file:///foo/bar.txt"));
console.log(path); // "/foo/bar.txt"

Bun.pathToFileURL()

將絕對路徑轉換成 file:// URL。

TypeScript
const url = Bun.pathToFileURL("/foo/bar.txt");
console.log(url); // "file:///foo/bar.txt"

Bun.gzipSync()

使用 zlib 的 GZIP 演算法壓縮 Uint8Array。

TypeScript
const buf = Buffer.from("hello".repeat(100)); // Buffer 繼承自 Uint8Array
const compressed = Bun.gzipSync(buf);

buf; // => Uint8Array(500)
compressed; // => Uint8Array(30)

可選傳入設定引數:

zlib 壓縮選項
expandable
export type ZlibCompressionOptions = {
  /**
   * 壓縮級別,範圍 -1 到 9。
   * - `-1` 預設壓縮級別(當前為 6)
   * - `0` 無壓縮
   * - `1` 最低壓縮,最快速度
   * - `9` 最佳壓縮,最慢速度
   */
  level?: -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
  /**
   * 內部壓縮狀態分配記憶體量。
   *
   * 值為 `1` 表示最小記憶體但較慢且壓縮率低。
   *
   * 值為 `9` 表示最大記憶體以最佳化速度,預設 8。
   */
  memLevel?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
  /**
   * 視窗大小的 base 2 對數(歷史資料緩衝區大小)。
   *
   * 較大值提高壓縮但增加記憶體消耗。
   *
   * 支援範圍:
   * - 9..15: 輸出包含 zlib 頭尾(Deflate)
   * - -9..-15: 輸出無 zlib 頭尾(Raw Deflate)
   * - 25..31 (16+9..15): 輸出有 gzip 頭尾(gzip)
   *
   * gzip 頭部無檔名、無額外資料、無註釋、無修改時間(置零)、無頭部 CRC。
   */
  windowBits?:
    | -9
    | -10
    | -11
    | -12
    | -13
    | -14
    | -15
    | 9
    | 10
    | 11
    | 12
    | 13
    | 14
    | 15
    | 25
    | 26
    | 27
    | 28
    | 29
    | 30
    | 31;
  /**
   * 調整壓縮演算法策略。
   *
   * - `Z_DEFAULT_STRATEGY`: 普通資料(預設)
   * - `Z_FILTERED`: 過濾器或預測器產生的資料
   * - `Z_HUFFMAN_ONLY`: 僅 Huffman 編碼(無字串匹配)
   * - `Z_RLE`: 限制匹配距離為 1(遊程編碼)
   * - `Z_FIXED`: 禁止使用動態 Huffman 編碼
   *
   * `Z_RLE` 效能接近 `Z_HUFFMAN_ONLY`,但對 PNG 等資料壓縮更優。
   *
   * `Z_FILTERED` 強制更多 Huffman 編碼,通常用於包含小且隨機分佈值的資料。
   */
  strategy?: number;
};

Bun.gunzipSync()

使用 zlib 的 GUNZIP 演算法解壓 Uint8Array。

TypeScript
const buf = Buffer.from("hello".repeat(100)); // Buffer 繼承自 Uint8Array
const compressed = Bun.gzipSync(buf);

const dec = new TextDecoder();
const uncompressed = Bun.gunzipSync(compressed);
dec.decode(uncompressed);
// => "hellohellohello..."

Bun.deflateSync()

使用 zlib 的 DEFLATE 演算法壓縮 Uint8Array。

TypeScript
const buf = Buffer.from("hello".repeat(100));
const compressed = Bun.deflateSync(buf);

buf; // => Buffer(500)
compressed; // => Uint8Array(12)

第二個引數支援與 Bun.gzipSync 相同的設定選項。


Bun.inflateSync()

使用 zlib 的 INFLATE 演算法解壓 Uint8Array。

TypeScript
const buf = Buffer.from("hello".repeat(100));
const compressed = Bun.deflateSync(buf);

const dec = new TextDecoder();
const decompressed = Bun.inflateSync(compressed);
dec.decode(decompressed);
// => "hellohellohello..."

Bun.zstdCompress() / Bun.zstdCompressSync()

使用 Zstandard 演算法壓縮 Uint8Array。

TypeScript
const buf = Buffer.from("hello".repeat(100));

// 同步壓縮
const compressedSync = Bun.zstdCompressSync(buf);
// 非同步壓縮
const compressedAsync = await Bun.zstdCompress(buf);

// 指定壓縮等級(1-22,預設 3)
const compressedLevel = Bun.zstdCompressSync(buf, { level: 6 });

Bun.zstdDecompress() / Bun.zstdDecompressSync()

使用 Zstandard 演算法解壓 Uint8Array。

TypeScript
const buf = Buffer.from("hello".repeat(100));
const compressed = Bun.zstdCompressSync(buf);

// 同步解壓
const decompressedSync = Bun.zstdDecompressSync(compressed);
// 非同步解壓
const decompressedAsync = await Bun.zstdDecompress(compressed);

const dec = new TextDecoder();
dec.decode(decompressedSync);
// => "hellohellohello..."

Bun.inspect()

將物件序列化為 string,其格式與 console.log 打印出的內容完全相同。

TypeScript
const obj = { foo: "bar" };
Bun.inspect(obj);
// => '{\n  foo: "bar",\n}'

const arr = new Uint8Array([1, 2, 3]);
Bun.inspect(arr);
// => "Uint8Array(3) [ 1, 2, 3 ]"

Bun.inspect.custom

Bun 用於實現 Bun.inspect 的符號。重寫它可自定義 Bun 列印物件的方式。它與 Node.js 中的 util.inspect.custom 完全相同。

TypeScript
class Foo {
  [Bun.inspect.custom]() {
    return "foo";
  }
}

const foo = new Foo();
console.log(foo); // => "foo"

Bun.inspect.table(tabularData, properties, options)

將表格資料格式化為字串。類似 console.table,但傳回字串而非列印。

TypeScript
console.log(
  Bun.inspect.table([
    { a: 1, b: 2, c: 3 },
    { a: 4, b: 5, c: 6 },
    { a: 7, b: 8, c: 9 },
  ]),
);
//
// ┌───┬───┬───┬───┐
// │   │ a │ b │ c │
// ├───┼───┼───┼───┤
// │ 0 │ 1 │ 2 │ 3 │
// │ 1 │ 4 │ 5 │ 6 │
// │ 2 │ 7 │ 8 │ 9 │
// └───┴───┴───┴───┘

傳入屬性名稱陣列,只顯示這些屬性。

TypeScript
console.log(
  Bun.inspect.table(
    [
      { a: 1, b: 2, c: 3 },
      { a: 4, b: 5, c: 6 },
    ],
    ["a", "c"],
  ),
);
//
// ┌───┬───┬───┐
// │   │ a │ c │
// ├───┼───┼───┤
// │ 0 │ 1 │ 3 │
// │ 1 │ 4 │ 6 │
// └───┴───┴───┘

傳入 { colors: true } 以啟用 ANSI 顏色。

TypeScript
console.log(
  Bun.inspect.table(
    [
      { a: 1, b: 2, c: 3 },
      { a: 4, b: 5, c: 6 },
    ],
    {
      colors: true,
    },
  ),
);

Bun.nanoseconds()

傳回當前 bun 行程啟動以來的納秒數(number 型別)。適合高精度計時和基準測試。

TypeScript
Bun.nanoseconds();
// => 7288958

Bun.readableStreamTo*()

Bun 實現了一組方便函式,可非同步消費 ReadableStream 的內容並轉換成各種二進位制格式。

TypeScript
const stream = (await fetch("https://bun.sh")).body;
stream; // => ReadableStream

await Bun.readableStreamToArrayBuffer(stream);
// => ArrayBuffer

await Bun.readableStreamToBytes(stream);
// => Uint8Array

await Bun.readableStreamToBlob(stream);
// => Blob

await Bun.readableStreamToJSON(stream);
// => object

await Bun.readableStreamToText(stream);
// => string

// 傳回所有塊組成的陣列
await Bun.readableStreamToArray(stream);
// => unknown[]

// 傳回所有塊組成的 FormData,編碼為 x-www-form-urlencoded
await Bun.readableStreamToFormData(stream);

// 傳回所有塊組成的 FormData,編碼為 multipart/form-data
await Bun.readableStreamToFormData(stream, multipartFormBoundary);

Bun.resolveSync()

使用 Bun 的內部模組解析演算法解析檔案路徑或模組說明符。第一個引數是要解析的路徑,第二個引數是“根目錄”。如果沒有匹配項,則會丟擲一個 Error。

TypeScript
Bun.resolveSync("./foo.ts", "/path/to/project");
// => "/path/to/project/foo.ts"

Bun.resolveSync("zod", "/path/to/project");
// => "/path/to/project/node_modules/zod/index.ts"

若想相對於當前工作目錄解析,傳入 process.cwd() 或 "."。

TypeScript
Bun.resolveSync("./foo.ts", process.cwd());
Bun.resolveSync("./foo.ts", "/path/to/project");

相對於當前檔案所在目錄解析,傳入 import.meta.dir。

TypeScript
Bun.resolveSync("./foo.ts", import.meta.dir);

Bun.stripANSI()

Bun.stripANSI(text: string): string

從字串中移除 ANSI 轉義碼。可用於移除終端輸出中的顏色和格式。

TypeScript
const coloredText = "\u001b[31mHello\u001b[0m \u001b[32mWorld\u001b[0m";
const plainText = Bun.stripANSI(coloredText);
console.log(plainText); // => "Hello World"

// 支援各種 ANSI 碼
const formatted = "\u001b[1m\u001b[4mBold and underlined\u001b[0m";
console.log(Bun.stripANSI(formatted)); // => "Bold and underlined"

Bun.stripANSI 比 strip-ansi npm 包更快:

terminal
bun bench/snippets/strip-ansi.mjs
Text
cpu: Apple M3 Max
runtime: bun 1.2.21 (arm64-darwin)

benchmark                               avg (min … max) p75 / p99
------------------------------------------------------- ----------
Bun.stripANSI      11 chars no-ansi        8.13 ns/iter   8.27 ns
                                   (7.45 ns … 33.59 ns)  10.29 ns

Bun.stripANSI      13 chars ansi          51.68 ns/iter  52.51 ns
                                 (46.16 ns … 113.71 ns)  57.71 ns

Bun.stripANSI  16,384 chars long-no-ansi 298.39 ns/iter 305.44 ns
                                (281.50 ns … 331.65 ns) 320.70 ns

Bun.stripANSI 212,992 chars long-ansi    227.65 µs/iter 234.50 µs
                                (216.46 µs … 401.92 µs) 262.25 µs
terminal
node bench/snippets/strip-ansi.mjs
Text
cpu: Apple M3 Max
runtime: node 24.6.0 (arm64-darwin)

benchmark                                avg (min … max) p75 / p99
-------------------------------------------------------- ---------
npm/strip-ansi      11 chars no-ansi      466.79 ns/iter 468.67 ns
                                 (454.08 ns … 570.67 ns) 543.67 ns

npm/strip-ansi      13 chars ansi         546.77 ns/iter 550.23 ns
                                 (532.74 ns … 651.08 ns) 590.35 ns

npm/strip-ansi  16,384 chars long-no-ansi   4.85 µs/iter   4.89 µs
                                     (4.71 µs … 5.00 µs)   4.98 µs

npm/strip-ansi 212,992 chars long-ansi      1.36 ms/iter   1.38 ms
                                     (1.27 ms … 1.73 ms)   1.49 ms


serialize 和 deserialize 來自 bun:jsc

Bun.wrapAnsi(input: string, columns: number, options?: WrapAnsiOptions): string

將文本換行至指定的列寬。它會保留 ANSI 轉義碼和超連結,並正確處理 Unicode/表情符號的寬度。這是 wrap-ansi npm 包的原生替代方案。

TypeScript
// 在 20 列處進行基本換行
Bun.wrapAnsi("The quick brown fox jumps over the lazy dog", 20);
// => "The quick brown fox\njumps over the lazy\ndog"

// 保留 ANSI 轉義碼:開放樣式會在每行末尾關閉,
// 並在下一行重新開啟,以確保每一行單獨渲染時都能正確顯示
Bun.wrapAnsi("\u001b[31mThe quick brown fox jumps over the lazy dog\u001b[0m", 20);
// => "\u001b[31mThe quick brown fox\u001b[39m\n\u001b[31mjumps over the lazy\u001b[39m\n\u001b[31mdog\u001b[0m"

選項

TypeScript
Bun.wrapAnsi("Hello World", 5, {
  hard: true, // 拆分超過列寬的單詞(預設值:false)
  wordWrap: true, // 在單詞邊界處換行(預設值:true)
  trim: true, // 去除每行開頭和結尾的空白字元(預設值:true)
  ambiguousIsNarrow: true, // 將不明確寬度的字元視為窄字元(預設值:true)
});
選項預設值描述
hardfalse如果為 true,當單詞超過列寬時,在單詞中間進行拆分。
wordWraptrue如果為 true,在單詞邊界處換行。如果為 false,則每行都嚴格在列寬處斷開。
trimtrue如果為 true,去除每行開頭和結尾的空白字元。
ambiguousIsNarrowtrue如果為 true,將不明確寬度的 Unicode 字元視為佔 1 列。如果為 false,則視為佔 2 列。

TypeScript 定義:

expandable
namespace Bun {
  export function wrapAnsi(
    /**
     * 要換行的字串
     */
    input: string,
    /**
     * 最大列寬
     */
    columns: number,
    /**
     * 換行選項
     */
    options?: {
      /**
       * 如果為 `true`,當單詞無法適應一行時,在單詞中間進行拆分。
       * 如果為 `false`,僅在單詞邊界處斷開。
       *
       * @default false
       */
      hard?: boolean;
      /**
       * 如果為 `true`,則儘可能在單詞邊界處換行。
       * 如果為 `false`,則每行都嚴格在列寬處斷開(字元會在限制所在位置被拆分,
       * 忽略單詞邊界)。
       *
       * @default true
       */
      wordWrap?: boolean;
      /**
       * 如果為 `true`,去除每行開頭和結尾的空白字元。
       * 如果為 `false`,保留空白字元。
       *
       * @default true
       */
      trim?: boolean;
      /**
       * 當字元寬度不明確且該選項為 `true` 時,將不明確寬度的字元按佔 1 列計算。
       * 如果為 `false`,則按佔 2 列計算。
       *
       * @default true
       */
      ambiguousIsNarrow?: boolean;
    },
  ): string;
}

serialize 和 deserialize 來自 bun:jsc

要將 JavaScript 值儲存到 SharedArrayBuffer 中並取回,請使用 "bun:jsc" 模組中的 serialize 和 deserialize。

JavaScript
import { serialize, deserialize } from "bun:jsc";

const buf = serialize({ foo: "bar" });
const obj = deserialize(buf);
console.log(obj); // => { foo: "bar" }

在內部,structuredClone 和 postMessage 使用相同的方式進行序列化和反序列化。serialize 和 deserialize 將底層的 HTML 結構化克隆演算法作為 SharedArrayBuffer 暴露給 JavaScript。


estimateShallowMemoryUsageOf 來自 bun:jsc

estimateShallowMemoryUsageOf 函式傳回物件的淺層記憶體佔用估計,單位是位元組,不包括其屬性或引用物件的記憶體。要準確測量單個物件的記憶體,推薦使用 Bun.generateHeapSnapshot。

JavaScript
import { estimateShallowMemoryUsageOf } from "bun:jsc";

const obj = { foo: "bar" };
const usage = estimateShallowMemoryUsageOf(obj);
console.log(usage); // => 16

const buffer = Buffer.alloc(1024 * 1024);
estimateShallowMemoryUsageOf(buffer);
// => 1048624

const req = new Request("https://bun.sh");
estimateShallowMemoryUsageOf(req);
// => 167

const array = Array(1024).fill({ a: 1 });
// 陣列通常不連續儲存,傳回結果不可用於衡量完整記憶體佔用(非錯誤)。
estimateShallowMemoryUsageOf(array);
// => 16