# tinybench 中文文档

规范地址：https://npmcn.com/package/tinybench/

版本：6\.2\.3
npm 元数据更新时间：2026-11-01T15:14:20.329Z
中文译文更新时间：2026-11-05T14:45:20.511Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/tinybench
原文对照：https://npmcn.com/package/tinybench/?lang=original
项目主页：https://github.com/tinylibs/tinybench#readme
源码仓库：https://github.com/tinylibs/tinybench

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：86.9 kB，5 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.0\.0
- 运行依赖：0 个
- 首次发布：2022-04-29T11:34:05.073Z
- 最新版本发布：2026-11-01T15:14:20.081Z
- 近 30 天下载量：464255336（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：71（近 12 个月 19 个）

## 中文简介

简单,小而轻重的基准库!

## 安装

```sh
npm install tinybench
```

也可以使用：`pnpm add tinybench`、`yarn add tinybench`、`bun add tinybench`

## README

# 小贝恩克

[![CI](https://github.com/tinylibs/tinybench/actions/workflows/qa.yml/badge.svg?branch=main)](https://github.com/tinylibs/tinybench/actions/workflows/qa.yml) [![NPM version](https://badgen.net/npm/v/tinybench?icon=npm)](https://www.npmjs.com/package/tinybench) [![Discord](https://badgen.net/discord/online-members/c3UUYNcHrU?icon=discord&label=discord&color=green)](https://discord.gg/c3UUYNcHrU) [![neostandard Javascript Code Style](https://badgen.net/static/code%20style/neostandard/green)](https://github.com/neostandard/neostandard)

一个简单、小而轻巧的基准库! 您可以在多个 JavaScript 运行时运行基准, Tinybench 完全基于 Web API, 并使用适当的时间 `process.hrtime` 或者说 `performance.now`。 。 。 .

-   基于环境的准确和准确的时间
-   统计分析延迟和通量值:标准偏差,出错幅度,相差,百分位等.
-   货币支持
-   `Event` 财务报告和审定财务报表 `EventTarget` 兼容事件
-   无依赖关系

_如果你需要更小的图书馆 比如小池或小池,请考虑提交 [RFC (RFC ) (法语)](https://github.com/tinylibs/rfcs)_

## 安装

```shell
$ npm install -D tinybench
```

## 使用量

你可以通过即时设定基准 `Bench` 分类并添加基准任务.

```js
import { Bench } from 'tinybench'

const bench = new Bench({ name: 'simple benchmark', time: 100 })

bench
  .add('faster task', () => {
    console.log('I am faster')
  })
  .add('slower task', async () => {
    await new Promise(resolve => setTimeout(resolve, 1)) // we wait 1ms :)
    console.log('I am slower')
  })

await bench.run()

console.log(bench.name)
console.table(bench.table())

// Output:
// simple benchmark
// ┌─────────┬───────────────┬───────────────────┬───────────────────────┬────────────────────────┬────────────────────────┬─────────┐
// │ (index) │ Task name     │ Latency avg (ns)  │ Latency med (ns)      │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
// ├─────────┼───────────────┼───────────────────┼───────────────────────┼────────────────────────┼────────────────────────┼─────────┤
// │ 0       │ 'faster task' │ '63768 ± 4.02%'   │ '58954 ± 15255.00'    │ '18562 ± 1.67%'        │ '16962 ± 4849'         │ 1569    │
// │ 1       │ 'slower task' │ '1542543 ± 7.14%' │ '1652502 ± 167851.00' │ '808 ± 19.65%'         │ '605 ± 67'             │ 65      │
// └─────────┴───────────────┴───────────────────┴───────────────────────┴────────────────────────┴────────────────────────┴─────────┘
```

这个 `add` 方法接受任务名称和任务函数,从而可以基准 这个! 这种方法返回引用到法官案例,所以有可能 用它来创造另一个任务,例如.

注意任务名称在某种情况下应该总是独一无二, 因为 Tinybench 存储基于任务 他们的名字在一个 `Map`。 。 。 .

还注意到 `tinybench` 默认不记录任何结果。 你可以提取相关数据 从 `bench.tasks` 或运行基准后的任何其他 API,并任意处理.

可在 [实例](https://npmcn.com/package/tinybench/examples/) 目录.

## 文档

### [财务问题](https://npmcn.com/package/tinybench/FAQ.md)

### [`Bench`](https://tinylibs.github.io/tinybench/classes/Bench.html)

### [`Task`](https://tinylibs.github.io/tinybench/classes/Task.html)

### [`TaskResult`](https://tinylibs.github.io/tinybench/types/TaskResult.html)

### `Events`

两者 `Task` 财务报告和审定财务报表 `Bench` 类扩展 `EventTarget` 对象。 因此,您可以使用通用 `addEventListener` 财务报告和审定财务报表 `removeEventListener` 方法。 。 .

#### [`BenchEvents`](https://tinylibs.github.io/tinybench/types/BenchEvents.html)

```js
// runs on each benchmark task's cycle
bench.addEventListener('cycle', (evt) => {
  const task = evt.task;
});

// runs when timer saturation is detected for a task's measured samples
bench.addEventListener('warning', (evt) => {
  const task = evt.task;
  const reason = evt.reason; // 'zero-dominated' | 'low-distinct' | 'zero-mad'
});
```

#### [`TaskEvents`](https://tinylibs.github.io/tinybench/types/TaskEvents.html)

```js
// runs only on this benchmark task's cycle
task.addEventListener('cycle', (evt) => {
  const task = evt.task;
});
```

### [`BenchEvent`](https://tinylibs.github.io/tinybench/interfaces/BenchEvent.html)

## 同步检测

Tinybench 自动检测任务函数是否同步 检查是否提供了函数 `AsyncFunction` 或者它返回一个 `Promise`,通过一次调用提供的函数.

您也可以明确设置 `async` 选项到 `true` 或者说 `false` 添加时 任务,从而避免被检测。 设定 `async: false` 只为了一个真正的 同步任务; 测量返回 a 函数的同步成本 `Promise`,通过 `overriddenDuration` 相反(见 [任务计量](https://npmcn.com/package/tinybench/#readme-task-supplied-measurements)) (中文(简体) ).

```ts
const bench = new Bench()

bench.add('asyncTask', async () => {}, { async: true })

bench.add('syncTask', () => {}, { async: false })

bench.add(
  'syncTaskReturningPromiseAsAsync',
  () => {
    return Promise.resolve()
  },
  { async: true }
)

await bench.run()
```

## 货币

-   何时 `mode` 设置为 `null` (默认),货币被禁用.
-   何时 `mode` 设置为“任务”,每个任务的迭代(调用任务函数)同时运行.
-   何时 `mode` 设置为“ 下” , 不同的任务同时运行 。 同时循环.

```ts
const bench = new Bench({
  concurrency: 'task', // The concurrency mode to determine how tasks are run.
  threshold: 10, // Maximum concurrent iterations within a task. Defaults to Infinity.
})
await bench.run()
```

与 `concurrency: null` 或者说 `'bench'`,每个任务都会持续到两个时间 符合预算和最低重迭数。 与 `concurrency: 'task'`, (中文(简体) ), 在达到正限时停止排期; `threshold` 限制该任务内同时重复而不是同时重复 基准任务。 取消重复限制 `iterations: 0` 需求 限定值 `threshold` (例如, `threshold: 10`),而不是默认值 `Infinity`这些规则也适用于: `warmupTime` 财务报告和审定财务报表 `warmupIterations` 内 `warmup()`。 。 。 . `Task.warmupSync()` 总是使用顺序规则,不管 的货币.

## 转换任务结果 `console.table()`

您可以将基准结果转换为适合 `console.table()` 使用 `bench.table()` 方法.

```ts
const table = bench.table()
console.table(table)
```

您也可以通过向表格提供转换函数来自定义表格输出 `table` 方法.

```ts
import { Bench, type ConsoleTableConverter, formatNumber, mToNs, type Task } from 'tinybench'

/**
 * The default converter function for console.table output.
 * Modify it as needed to customize the table format.
 */
const defaultConverter: ConsoleTableConverter = (task: Task): Record<string, number | string> => {
  const state = task.result.state
  return {
    'Task name': task.name,
    ...(state === 'aborted-with-statistics' || state === 'completed'
      ? {
          'Latency avg (ns)': `${formatNumber(mToNs(task.result.latency.mean))} \xb1 ${formatNumber(task.result.latency.rme)}%`,
          'Latency med (ns)': `${formatNumber(mToNs(task.result.latency.p50))} \xb1 ${formatNumber(mToNs(task.result.latency.mad))}`,
          'Throughput avg (ops/s)': `${Math.round(task.result.throughput.mean).toString()} \xb1 ${formatNumber(task.result.throughput.rme)}%`,
          'Throughput med (ops/s)': `${Math.round(task.result.throughput.p50).toString()} \xb1 ${Math.round(task.result.throughput.mad).toString()}`,
          Samples: task.result.latency.samplesCount,
        }
      : state !== 'errored'
        ? {
            'Latency avg (ns)': 'N/A',
            'Latency med (ns)': 'N/A',
            'Throughput avg (ops/s)': 'N/A',
            'Throughput med (ops/s)': 'N/A',
            Samples: 'N/A',
            Remarks: state,
          }
        : {
            Error: task.result.error.message,
            Stack: task.result.error.stack ?? 'N/A',
          }),
    ...(state === 'aborted-with-statistics' && {
      Remarks: state,
    }),
  }
}

const bench = new Bench({ name: 'custom table benchmark', time: 100 })
// add tasks...

console.table(bench.table(defaultConverter))
```

## 保留样本

默认情况下, Tinybench 不保存样本 `latency` 财务报告和审定财务报表 `throughput` 改为 最小化内存使用。 需要原始样本时启用保留样本 绘图、自定义分析或输出结果.

通过设置 `retainSamples` 选项到 `true` 创建时 `Bench` 实例:

```ts
const bench = new Bench({ retainSamples: true })
```

通过设置 `retainSamples` 选项到 `true` 添加任务时 :

```ts
bench.add(
  'task with samples',
  () => {
    // Task logic here
  },
  { retainSamples: true }
)
```

## 时间戳提供商

Tinybench可以利用不同的时间戳提供商来测量时间间隔. 默认使用 `performance.now()`。 。 。 .

这个 `timestampProvider` 选项可以在创建 `Bench` 举个例子 这个 接受一个 `TimestampProvider` 普通对象或缩写 供应商 `hrtimeNow` 财务报告和审定财务报表 `performanceNow`。 。 。 .

如果您使用 `bun` 运行时间,您也可以使用 `bunNanoseconds` 缩写.

你可以设置 `timestampProvider` 改为 `auto` 让Tinybench选择最多 根据运行时间提供精确可用的时间戳 .

```ts
import { Bench } from 'tinybench'

const bench = new Bench({
  timestampProvider: 'hrtimeNow', // or 'performanceNow', 'bunNanoseconds', 'auto'
})
```

如果您想要提供自定义的时间戳提供者, 您可以创建执行对象 页:1 `TimestampProvider` 接口 :

```ts
import { Bench, type TimestampProvider } from 'tinybench'

// Custom timestamp provider using Date.now()
const dateNowTimestampProvider: TimestampProvider = {
  name: 'dateNow', // name of the provider
  fn: Date.now, // function that returns the current timestamp
  toMs: ts => Number(ts), // convert the timestamp to milliseconds
  fromMs: ts => ts, // convert milliseconds to the format used by fn()
}

const bench = new Bench({
  timestampProvider: dateNowTimestampProvider,
})
```

您也可以设置 `now` 选项到返回当前时间戳的函数. 将改为 `TimestampProvider` 内部.

```ts
import { Bench } from 'tinybench'

const bench = new Bench({
  now: Date.now,
})
```

## 超头修正

每个计时器呼叫( E)`performance.now()`, (中文(简体) ), `process.hrtime.bigint()`拥有一个 非零呼叫费用 `C`。用于一个任务,其真正持续时间 `X` 可比较 改为 `C`,原始测量样本 `X + C` 以计时器为主 而不是任务.

何时 `subtractTimerOverhead: true` 设置, 一个估计数 `Ĉ` 计算 施工时间一次通过 [`calibrateTimerOverhead`](https://tinylibs.github.io/tinybench/functions/calibrateTimerOverhead.html), (中文(简体) ), 财务报告和审定财务报表 `Math.max(0, raw_sample - Ĉ)` 用作每个非重叠样本 在计算统计数据之前.

```ts
const bench = new Bench({ subtractTimerOverhead: true })
console.log(bench.timerOverhead) // calibrated Ĉ in ms (or undefined)
```

校正辅助器也出口给直接使用,其中 可配置的估算战略`'median'` 默认,或 `'min'` 编号 : `'p05'`:

```ts
import { calibrateTimerOverhead, hrtimeNowTimestampProvider } from 'tinybench'

const overhead = calibrateTimerOverhead(hrtimeNowTimestampProvider, {
  estimator: 'p05',
  pairs: 1024,
  warmupPairs: 64,
})
```

**出出洞来.**

-   与 `concurrency: 'task'` - 管理费用经过校正 按顺序排列,不反映同时执行费用. 建筑业(和 `run()`如果两者都设定了,则投掷.
-   用于次级项目测量`X ≈ Ĉ`(b) 与《京都议定书》 `max(0, …)` 夹子 截取下尾和偏差统计; 偏好 `overriddenDuration`。 。 。 .
-   当计时器过于粗糙,无法解决呼叫费用时——不到一半 校正对对产生正三角洲(呼叫成本) `C < R / 2`, (中文(简体) ), 例如,a `Date.now`\- 级计时器 `>= 1 ms` ——校正 返回时 `0` 选项变成禁用.
-   每个样本都包含一个单一的任务调用,而不是一个分批循环,所以 每样计时器地板 `C` 未摊销。 这是蓄意取舍: 它产生真实的每个样本分布(百分比、MAD、饱和度) 以较高分公司为代价`C` 噪音地板。 用于以下工作 计时器谷物, 使用 `overriddenDuration`。 。 。 .
-   `Ĉ` 不覆盖同步任务的 `await` 微任务转弯——即: 在所测量的窗口内,但没有校正对——所以 亚微秒样本即使与 `subtractTimerOverhead`。 。 。 . 使用 `overriddenDuration` 用于这种分解工作.

## 任务计量

### 每一样本持续时间(`overriddenDuration`(中文(简体) )

任务函数可能返回包含 `overriddenDuration` (以毫秒计). 该值被记录在计时器测量样本的外: 定时器仍然将任务函数置于括号内,但其测量是 已丢弃,未对替换的间接费用校正 数值。 用于外部定时工作或次级管理项目测量 计时器无法解决.

```ts
import type { FnReturnedObject } from 'tinybench'

bench.add('externally-timed', (): FnReturnedObject => {
  const start = process.hrtime.bigint()
  doWork()
  const elapsedMs = Number(process.hrtime.bigint() - start) / 1e6
  return { overriddenDuration: elapsedMs }
})
```

过时的样本不包括在 `Task.detectedResolution` 财务报告和审定财务报表 从计时器饱和度检测.

### 重置费用(`overriddenIterationCost`(中文(简体) )

当一次重复数次内调时,每调值值你 想要在统计中与重复的实际成本不同 页:1 `time` 编号 : `warmupTime` 预算。 返回时 `overriddenIterationCost` (ms) 宣布整个迭代的壁时成本:

```ts
import type { FnReturnedObject } from 'tinybench'

bench.add('batched', () => {
  const innerCalls = 100
  const start = process.hrtime.bigint()
  for (let i = 0; i < innerCalls; i++) parse(input)
  const elapsedMs = Number(process.hrtime.bigint() - start) / 1e6
  return {
    overriddenDuration: elapsedMs / innerCalls, // mean per call in this batch
    overriddenIterationCost: elapsedMs, // budget cost of the iteration
  } satisfies FnReturnedObject
})
```

每个样本是每批呼叫的平均持续时间。 百分比和百分比 分散描述这些批次手段,而不是批次中个别的呼叫.

语义:

-   样本使用有效的 `overriddenDuration`,否则计时器测量 持续时间。 顺序预算使用有效的 `overriddenIterationCost`, (中文(简体) ), 否则,在定时器 -- -- 超头修正之前,样本。 仅返回 `overriddenDuration` 因此,保持历史行为.
-   任务当前 `run()` 财务报告和审定财务报表 `warmup()` 使用真实的时钟进行预算 不检查 `overriddenIterationCost` (既无存在也无价值). 每项任务的费用 `concurrency: 'bench'` 内 `Task.warmupSync()` 无论币种如何.
-   两个字段的验证方法相同(无限数字为 ^ 0, `-0` 包含);无效值被视为不存在.
-   成本领域必须报告为 `in` 运算符(拥有或拥有) 页:1 缺出密钥的代理默认不是宣布的成本 。 错误 在检查或读取此字段时,则被视为一笔没有的费用.
-   费用不影响定时器-管理头修正或定时器诊断; 它们在样本上运作. `result.totalTime` 财务报告和审定财务报表 `period` 仍为 样本来源。 仅返回成本 留下的样本计时器, 因此,计时器饱和度警告仍然会发生.
-   申报的费用没有根据实际情况加以核实: 墙上小时成本是 `C` 但宣布为 `O` 运行到大约 `time × C / O` 何时 `O < C`,并缩短当 `O > C`备注 时间预算支配着最小重迭数.
-   **警告,我马上回来.** 重复费用 `0` (或 `-0`无法满足正数 相接的时间预算;微小的正成本可能使达到不切实际. 与 `time: 0`,运行可以在最小重迭数完成。 一样 规则适用于热身。 从外部定时器取消需要生成 切换到事件循环,不能中断 `runSync()`; 见 [执行期间中止](https://npmcn.com/package/tinybench/#readme-abort-during-execution)。 。 。 .

## 定时诊断

之后 `bench.run()` (或 `runSync()`),每个任务都会暴露 `detectedResolution`:至少发生最小的阳性耐久性样本 两次,如果没有重复,则为最小的正样本。 只有计时器 考虑在任何高层修正之后的样本;如果无正面的, 结果 `undefined`。这是基于样本的热力学,不是保证 绑定在计时器的分辨率.

```ts
const task = bench.getTask('foo')
console.log(task?.detectedResolution) // e.g. 0.000041 (≈ 41 ns)
```

至少有10个这样的样本,小箱发送a `'warning'` 活动 任务和板凳,如果超过一半为零,则少于 `max(3, min(10, ⌊n / 1000⌋))` 出现差异值,或 MAD 为 0, 与 `n > 100`。该事件带有匹配 [`TimerSaturationReason`](https://tinylibs.github.io/tinybench/types/TimerSaturationReason.html)数字 :

```ts
bench.addEventListener('warning', evt => {
  console.warn(`timer-saturated: ${evt.task?.name} — ${evt.reason}`)
})
```

同样的高压和估测器被曝光为独立的助手 自定义分析 : [`detectTimerSaturation`](https://tinylibs.github.io/tinybench/functions/detectTimerSaturation.html), (中文(简体) ), [`classifyTimerSaturation`](https://tinylibs.github.io/tinybench/functions/classifyTimerSaturation.html), (中文(简体) ), 财务报告和审定财务报表 [`estimateResolution`](https://tinylibs.github.io/tinybench/functions/estimateResolution.html)。 。 。 .

## 中止基准

Tinybench 支持使用中止基准 `AbortSignal` 在法官一级和任务一级:

### 座椅级中止

将一个信号传递到 `Bench` 构造器 :

```ts
const controller = new AbortController()

const bench = new Bench({ signal: controller.signal })

bench
  .add('task1', () => {
    // This will be aborted
  })
  .add('task2', () => {
    // This will also be aborted
  })

// Abort all tasks
controller.abort()

await bench.run()
// Both tasks will be aborted
```

### 任务级别中止

通过向任务选项传递信号中止单个任务而不影响其他任务:

```ts
const controller = new AbortController()

const bench = new Bench()

bench
  .add(
    'abortable task',
    () => {
      // This task can be aborted independently
    },
    { signal: controller.signal }
  )
  .add('normal task', () => {
    // This task will continue normally
  })

// Abort only the first task
controller.abort()

await bench.run()
// Only 'abortable task' will be aborted, 'normal task' continues
```

### 执行期间中止

你可以中止基准 当它们运行时:

```ts
const controller = new AbortController()

const bench = new Bench({ time: 10000 }) // Long-running benchmark

bench.add(
  'long task',
  async () => {
    await new Promise(resolve => setTimeout(resolve, 100))
  },
  { signal: controller.signal }
)

// Abort after 1 second
setTimeout(() => controller.abort(), 1000)

await bench.run()
// Task will stop after ~1 second instead of running for 10 seconds
```

计时器触发取消需要任务或钩子向 事件循环,例如等待 I/O。 等待一个已经解开的承诺 这还不够。 单位 `runSync()`,任务或同步钩可以调用 `controller.abort()` ,但外部计时器 不能中断运行.

### 中止事件

两者 `Bench` 财务报告和审定财务报表 `Task` 发射 `abort` 中止时的事件 :

```ts
const controller = new AbortController()
const bench = new Bench()

bench.add(
  'task',
  () => {
    // Task function
  },
  { signal: controller.signal }
)

const task = bench.getTask('task')
if (!task) {
  throw new Error('Task not found')
}

// Listen for abort events
task.addEventListener('abort', () => {
  console.log('Task aborted!')
})

bench.addEventListener('abort', () => {
  console.log('Bench received abort event!')
})

controller.abort()
await bench.run()
```

**说明:** 已中止的任务 `task.result.state` 等于 `'aborted'` 或者说 `'aborted-with-statistics'`。已在进行的重复可能在此之前完成 运行返回.

## 前作艺术

-   [基准.js](https://github.com/bestiejs/benchmark.js)
-   [米塔塔语](https://github.com/evanwashere/mitata/)
-   [纳米-纳克](https://github.com/poolifier/tatami-ng)
-   [贝玛](https://github.com/prisma-labs/bema)

## 作者数

| [![](https://avatars.githubusercontent.com/u/37929992?v=4)  
穆罕默德·巴盖尔](https://github.com/Aslemammad) |
| --- |

## 贷项

| [![](https://avatars.githubusercontent.com/u/5059100?v=4)  
乌兹洛帕克](https://github.com/uzlopak) | [![](https://avatars.githubusercontent.com/u/36070057?v=4)  
波约](https://github.com/poyoho) |
| --- | --- |

## 捐款

请随意为项目创造问题/讨论,然后是公关!

## 发起人

你的赞助能对我们继续开放源码的工作产生巨大影响!

[![](https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg)](https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg)

## 常见问题

### tinybench 是什么？

简单,小而轻重的基准库\!

### 如何安装 tinybench？

在项目目录运行 npm install tinybench，或使用 pnpm add / yarn add / bun add。

### tinybench 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### tinybench 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### tinybench 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### tinybench 可以商用吗？

tinybench 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### tinybench 的下载量有多少？

根据 npm 官方下载统计，tinybench 在 2026/10/05 – 2026/11/03 这 30 天内被下载 464,255,336 次，日均约 15,475,178 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### tinybench 还在维护吗？

最新版本 6\.2\.3 发布于 2026/11/01（4 天前）；至今共发布 71 个版本，其中过去 12 个月发布了 19 个；首次发布于 2022/04/29。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

