Vitest 性能测试 #

性能测试概述 #

Vitest 内置了基准测试(Benchmark)功能,基于 Tinybench 实现,可以测量代码执行时间、比较不同实现的性能差异。

性能测试的作用 #

text
┌─────────────────────────────────────────────────────────────┐
│                    性能测试的作用                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 性能对比                                                │
│     比较不同实现的执行效率                                    │
│                                                             │
│  2. 回归检测                                                │
│     确保优化后性能没有下降                                    │
│                                                             │
│  3. 瓶颈识别                                                │
│     找出性能瓶颈点                                           │
│                                                             │
│  4. 文档化                                                  │
│     为性能要求提供量化依据                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

基本用法 #

bench 函数 #

使用 bench 函数创建性能测试:

typescript
import { bench, describe } from 'vitest'

describe('sorting algorithms', () => {
  bench('bubble sort', () => {
    const arr = [5, 3, 8, 4, 2]
    bubbleSort(arr)
  })
  
  bench('quick sort', () => {
    const arr = [5, 3, 8, 4, 2]
    quickSort(arr)
  })
})

运行性能测试 #

bash
# 运行性能测试
vitest bench

# 运行特定文件
vitest bench sort.bench.ts

# Watch 模式
vitest bench --watch

输出示例 #

text
✓ sort.bench.ts (2) 1234ms
  ✓ bubble sort    1234.56 ns/iter   1000 iterations
  ✓ quick sort      456.78 ns/iter   1000 iterations

  quick sort is 2.70x faster than bubble sort

性能测试结构 #

基本结构 #

typescript
import { bench, describe } from 'vitest'

describe('performance suite', () => {
  bench('test name', () => {
    // 要测试的代码
  })
})

嵌套套件 #

typescript
import { bench, describe } from 'vitest'

describe('string operations', () => {
  describe('concatenation', () => {
    bench('using + operator', () => {
      let result = ''
      for (let i = 0; i < 100; i++) {
        result += 'a'
      }
    })
    
    bench('using array join', () => {
      const arr = Array(100).fill('a')
      arr.join('')
    })
  })
  
  describe('search', () => {
    bench('indexOf', () => {
      'hello world'.indexOf('world')
    })
    
    bench('includes', () => {
      'hello world'.includes('world')
    })
  })
})

测试选项 #

时间和迭代次数 #

typescript
import { bench, describe } from 'vitest'

describe('options', () => {
  bench('with options', () => {
    // 测试代码
  }, {
    time: 1000,      // 运行时间(毫秒)
    iterations: 100, // 最小迭代次数
    warmupIterations: 5, // 预热迭代次数
    warmupTime: 100, // 预热时间(毫秒)
  })
})

配置默认选项 #

typescript
// vitest.config.ts
import { defineConfig } from 'vitest'

export default defineConfig({
  test: {
    benchmark: {
      include: ['**/*.bench.ts'],
      exclude: ['node_modules'],
      time: 1000,
      iterations: 100,
    },
  },
})

准备和清理 #

setup 和 teardown #

typescript
import { bench, describe } from 'vitest'

describe('with setup', () => {
  let data: number[]
  
  // 每次迭代前执行
  bench.beforeEach(() => {
    data = Array(1000).fill(0).map(() => Math.random())
  })
  
  // 每次迭代后执行
  bench.afterEach(() => {
    data = []
  })
  
  bench('sort array', () => {
    data.sort((a, b) => a - b)
  })
})

全局 setup #

typescript
import { bench, describe, beforeAll, afterAll } from 'vitest'

describe('global setup', () => {
  let database: Database
  
  beforeAll(async () => {
    database = await connectDatabase()
  })
  
  afterAll(async () => {
    await database.disconnect()
  })
  
  bench('query', async () => {
    await database.query('SELECT 1')
  })
})

异步性能测试 #

测试异步代码 #

typescript
import { bench, describe } from 'vitest'

describe('async operations', () => {
  bench('promise', async () => {
    await Promise.resolve(42)
  })
  
  bench('fetch', async () => {
    await fetch('/api/data')
  })
  
  bench('multiple promises', async () => {
    await Promise.all([
      Promise.resolve(1),
      Promise.resolve(2),
      Promise.resolve(3),
    ])
  })
})

性能对比示例 #

字符串操作对比 #

typescript
import { bench, describe } from 'vitest'

describe('string operations', () => {
  const str = 'hello world, this is a test string'
  
  bench('substring', () => {
    str.substring(0, 10)
  })
  
  bench('slice', () => {
    str.slice(0, 10)
  })
  
  bench('split + join', () => {
    str.split(' ').join('-')
  })
  
  bench('replaceAll', () => {
    str.replaceAll(' ', '-')
  })
})

数组操作对比 #

typescript
import { bench, describe } from 'vitest'

describe('array operations', () => {
  const arr = Array(1000).fill(0).map((_, i) => i)
  
  bench('for loop', () => {
    let sum = 0
    for (let i = 0; i < arr.length; i++) {
      sum += arr[i]
    }
  })
  
  bench('for...of', () => {
    let sum = 0
    for (const num of arr) {
      sum += num
    }
  })
  
  bench('forEach', () => {
    let sum = 0
    arr.forEach(num => sum += num)
  })
  
  bench('reduce', () => {
    arr.reduce((sum, num) => sum + num, 0)
  })
})

对象操作对比 #

typescript
import { bench, describe } from 'vitest'

describe('object operations', () => {
  const obj = { a: 1, b: 2, c: 3, d: 4, e: 5 }
  
  bench('Object.keys', () => {
    Object.keys(obj)
  })
  
  bench('Object.values', () => {
    Object.values(obj)
  })
  
  bench('Object.entries', () => {
    Object.entries(obj)
  })
  
  bench('for...in', () => {
    const keys: string[] = []
    for (const key in obj) {
      keys.push(key)
    }
  })
})

函数调用对比 #

typescript
import { bench, describe } from 'vitest'

describe('function calls', () => {
  function regularFunction(x: number) {
    return x * 2
  }
  
  const arrowFunction = (x: number) => x * 2
  
  const obj = {
    method(x: number) {
      return x * 2
    },
  }
  
  bench('regular function', () => {
    regularFunction(42)
  })
  
  bench('arrow function', () => {
    arrowFunction(42)
  })
  
  bench('method call', () => {
    obj.method(42)
  })
})

复杂数据结构测试 #

Map vs Object #

typescript
import { bench, describe } from 'vitest'

describe('Map vs Object', () => {
  const obj: Record<string, number> = {}
  const map = new Map<string, number>()
  
  // 初始化数据
  for (let i = 0; i < 1000; i++) {
    obj[`key${i}`] = i
    map.set(`key${i}`, i)
  }
  
  bench('Object get', () => {
    obj['key500']
  })
  
  bench('Map get', () => {
    map.get('key500')
  })
  
  bench('Object set', () => {
    obj['newKey'] = 1
  })
  
  bench('Map set', () => {
    map.set('newKey', 1)
  })
  
  bench('Object has', () => {
    'key500' in obj
  })
  
  bench('Map has', () => {
    map.has('key500')
  })
})

Set vs Array #

typescript
import { bench, describe } from 'vitest'

describe('Set vs Array', () => {
  const arr = Array(1000).fill(0).map((_, i) => i)
  const set = new Set(arr)
  
  bench('Array includes', () => {
    arr.includes(500)
  })
  
  bench('Set has', () => {
    set.has(500)
  })
  
  bench('Array push', () => {
    arr.push(1001)
  })
  
  bench('Set add', () => {
    set.add(1001)
  })
})

算法性能测试 #

排序算法对比 #

typescript
import { bench, describe } from 'vitest'

function bubbleSort(arr: number[]) {
  const result = [...arr]
  for (let i = 0; i < result.length; i++) {
    for (let j = 0; j < result.length - i - 1; j++) {
      if (result[j] > result[j + 1]) {
        [result[j], result[j + 1]] = [result[j + 1], result[j]]
      }
    }
  }
  return result
}

function quickSort(arr: number[]): number[] {
  if (arr.length <= 1) return arr
  const pivot = arr[0]
  const left = arr.slice(1).filter(x => x < pivot)
  const right = arr.slice(1).filter(x => x >= pivot)
  return [...quickSort(left), pivot, ...quickSort(right)]
}

function nativeSort(arr: number[]) {
  return [...arr].sort((a, b) => a - b)
}

describe('sorting algorithms', () => {
  const smallArray = Array(10).fill(0).map(() => Math.random())
  const mediumArray = Array(100).fill(0).map(() => Math.random())
  const largeArray = Array(1000).fill(0).map(() => Math.random())
  
  describe('small array (10 elements)', () => {
    bench('bubble sort', () => bubbleSort(smallArray))
    bench('quick sort', () => quickSort(smallArray))
    bench('native sort', () => nativeSort(smallArray))
  })
  
  describe('medium array (100 elements)', () => {
    bench('bubble sort', () => bubbleSort(mediumArray))
    bench('quick sort', () => quickSort(mediumArray))
    bench('native sort', () => nativeSort(mediumArray))
  })
  
  describe('large array (1000 elements)', () => {
    bench('quick sort', () => quickSort(largeArray))
    bench('native sort', () => nativeSort(largeArray))
    // bubble sort 太慢,跳过
  })
})

查找算法对比 #

typescript
import { bench, describe } from 'vitest'

function linearSearch(arr: number[], target: number): number {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) return i
  }
  return -1
}

function binarySearch(arr: number[], target: number): number {
  let left = 0
  let right = arr.length - 1
  
  while (left <= right) {
    const mid = Math.floor((left + right) / 2)
    if (arr[mid] === target) return mid
    if (arr[mid] < target) left = mid + 1
    else right = mid - 1
  }
  
  return -1
}

describe('search algorithms', () => {
  const arr = Array(10000).fill(0).map((_, i) => i)
  const target = 5000
  
  bench('linear search', () => {
    linearSearch(arr, target)
  })
  
  bench('binary search', () => {
    binarySearch(arr, target)
  })
  
  bench('indexOf', () => {
    arr.indexOf(target)
  })
})

性能测试最佳实践 #

1. 使用真实数据 #

typescript
import { bench, describe } from 'vitest'

// 好的做法:使用真实大小的数据
describe('realistic data', () => {
  const realisticData = loadRealData() // 加载真实数据
  
  bench('process data', () => {
    processData(realisticData)
  })
})

// 不好的做法:使用过小的数据
describe('unrealistic data', () => {
  const smallData = [1, 2, 3] // 太小,无法反映真实性能
  
  bench('process data', () => {
    processData(smallData)
  })
})

2. 避免优化干扰 #

typescript
import { bench, describe } from 'vitest'

// 好的做法:使用结果,防止被优化掉
describe('avoid optimization', () => {
  bench('calculate', () => {
    let result = 0
    for (let i = 0; i < 1000; i++) {
      result += i
    }
    // 使用结果
    return result
  })
})

3. 预热测试 #

typescript
import { bench, describe } from 'vitest'

describe('with warmup', () => {
  bench('cached operation', () => {
    // 第一次执行可能较慢(缓存未命中)
    // 预热后测量更准确
    expensiveOperation()
  }, {
    warmupIterations: 10,
    warmupTime: 100,
  })
})

4. 多次运行取平均 #

typescript
import { bench, describe } from 'vitest'

describe('multiple runs', () => {
  bench('stable measurement', () => {
    // Vitest 自动多次运行
    operation()
  }, {
    time: 1000,      // 运行 1 秒
    iterations: 100, // 至少 100 次
  })
})

5. 隔离测试环境 #

typescript
import { bench, describe } from 'vitest'

describe('isolated environment', () => {
  let data: number[]
  
  bench.beforeEach(() => {
    // 每次迭代前重置数据
    data = generateData()
  })
  
  bench('isolated test', () => {
    processData(data)
  })
})

性能测试报告 #

输出解读 #

text
✓ bench.bench.ts (2) 1234ms
  ✓ operation A    123.45 ns/iter   10000 iterations
  ✓ operation B     67.89 ns/iter   15000 iterations

  operation B is 1.82x faster than operation A
指标 说明
ns/iter 每次迭代的平均时间(纳秒)
iterations 总迭代次数
x faster 性能倍数对比

JSON 报告 #

typescript
// vitest.config.ts
import { defineConfig } from 'vitest'

export default defineConfig({
  test: {
    benchmark: {
      reporters: ['default', 'json'],
    },
  },
})

性能测试速查表 #

函数 说明
bench(name, fn) 创建性能测试
bench.beforeEach(fn) 每次迭代前执行
bench.afterEach(fn) 每次迭代后执行
describe(name, fn) 创建测试套件
选项 说明
time 运行时间(毫秒)
iterations 最小迭代次数
warmupTime 预热时间
warmupIterations 预热迭代次数

下一步 #

现在你已经掌握了性能测试,接下来学习 高级特性 了解 Vitest 的高级功能!

最后更新:2026-03-28