Skip to content

memo

创建一个记忆化函数,缓存函数结果以避免重复计算。

基础用法

typescript
import { memo } from 'radash'

const expensiveCalculation = memo((n: number) => {
  console.log('Computing...')
  return n * n * n
})

console.log(expensiveCalculation(5)) // Computing... 125
console.log(expensiveCalculation(5)) // 125 (从缓存返回)
console.log(expensiveCalculation(3)) // Computing... 27
console.log(expensiveCalculation(5)) // 125 (从缓存返回)

语法

typescript
function memo<T extends (...args: any[]) => any>(
  fn: T,
  options?: {
    maxSize?: number
    ttl?: number
  }
): T

参数

  • fn (function): 要记忆化的函数
  • options (object, 可选): 配置选项
    • maxSize (number, 可选): 缓存的最大条目数
    • ttl (number, 可选): 缓存条目的生存时间(毫秒)

返回值

返回一个记忆化后的函数,具有相同的签名但会缓存结果。

示例

基本记忆化

typescript
import { memo } from 'radash'

const fibonacci = memo((n: number): number => {
  console.log(`Computing fibonacci(${n})`)
  if (n <= 1) return n
  return fibonacci(n - 1) + fibonacci(n - 2)
})

console.log(fibonacci(10)) // 计算并缓存
console.log(fibonacci(10)) // 从缓存返回
console.log(fibonacci(5))  // 从缓存返回

复杂参数记忆化

typescript
import { memo } from 'radash'

interface User {
  id: number
  name: string
  age: number
}

const getUserStats = memo((users: User[], filter: string) => {
  console.log('Computing user stats...')
  
  const filtered = users.filter(user => 
    user.name.toLowerCase().includes(filter.toLowerCase())
  )
  
  return {
    count: filtered.length,
    averageAge: filtered.reduce((sum, user) => sum + user.age, 0) / filtered.length,
    names: filtered.map(user => user.name)
  }
})

const users: User[] = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 },
  { id: 3, name: 'Charlie', age: 35 }
]

console.log(getUserStats(users, 'alice')) // 计算
console.log(getUserStats(users, 'alice')) // 从缓存返回
console.log(getUserStats(users, 'bob'))   // 计算

异步函数记忆化

typescript
import { memo } from 'radash'

const fetchUserData = memo(async (userId: number) => {
  console.log(`Fetching user ${userId}...`)
  const response = await fetch(`/api/users/${userId}`)
  return response.json()
})

// 使用记忆化的异步函数
async function getUser(userId: number) {
  const user = await fetchUserData(userId)
  console.log('User:', user)
  return user
}

// 第一次调用会发起请求
await getUser(1)
// 第二次调用会从缓存返回
await getUser(1)

带缓存大小限制

typescript
import { memo } from 'radash'

const expensiveFunction = memo((input: string) => {
  console.log(`Computing for: ${input}`)
  return input.split('').reverse().join('')
}, { maxSize: 3 })

console.log(expensiveFunction('hello')) // 计算
console.log(expensiveFunction('world')) // 计算
console.log(expensiveFunction('test'))  // 计算
console.log(expensiveFunction('hello')) // 从缓存返回
console.log(expensiveFunction('new'))   // 计算,会清除最旧的缓存

带生存时间的缓存

typescript
import { memo } from 'radash'

const getCurrentTime = memo(() => {
  console.log('Getting current time...')
  return new Date().toISOString()
}, { ttl: 5000 }) // 5秒缓存

console.log(getCurrentTime()) // 计算
console.log(getCurrentTime()) // 从缓存返回

// 5秒后
setTimeout(() => {
  console.log(getCurrentTime()) // 重新计算
}, 6000)

对象参数记忆化

typescript
import { memo } from 'radash'

const processConfig = memo((config: Record<string, any>) => {
  console.log('Processing config...')
  return {
    ...config,
    processed: true,
    timestamp: Date.now()
  }
})

const config1 = { theme: 'dark', language: 'en' }
const config2 = { theme: 'light', language: 'zh' }

console.log(processConfig(config1)) // 计算
console.log(processConfig(config1)) // 从缓存返回
console.log(processConfig(config2)) // 计算

数组参数记忆化

typescript
import { memo } from 'radash'

const calculateArrayStats = memo((numbers: number[]) => {
  console.log('Calculating array stats...')
  return {
    sum: numbers.reduce((acc, num) => acc + num, 0),
    average: numbers.reduce((acc, num) => acc + num, 0) / numbers.length,
    min: Math.min(...numbers),
    max: Math.max(...numbers)
  }
})

const numbers1 = [1, 2, 3, 4, 5]
const numbers2 = [6, 7, 8, 9, 10]

console.log(calculateArrayStats(numbers1)) // 计算
console.log(calculateArrayStats(numbers1)) // 从缓存返回
console.log(calculateArrayStats(numbers2)) // 计算

多参数记忆化

typescript
import { memo } from 'radash'

const complexCalculation = memo((a: number, b: number, operation: string) => {
  console.log(`Computing ${a} ${operation} ${b}...`)
  
  switch (operation) {
    case 'add':
      return a + b
    case 'multiply':
      return a * b
    case 'divide':
      return a / b
    default:
      return a - b
  }
})

console.log(complexCalculation(5, 3, 'add'))      // 计算
console.log(complexCalculation(5, 3, 'add'))      // 从缓存返回
console.log(complexCalculation(5, 3, 'multiply')) // 计算

递归函数记忆化

typescript
import { memo } from 'radash'

const factorial = memo((n: number): number => {
  console.log(`Computing factorial(${n})`)
  if (n <= 1) return 1
  return n * factorial(n - 1)
})

console.log(factorial(5)) // 计算
console.log(factorial(5)) // 从缓存返回
console.log(factorial(3)) // 从缓存返回(因为factorial(3)在计算factorial(5)时已经计算过)

条件记忆化

typescript
import { memo } from 'radash'

const conditionalMemo = memo((value: string, shouldCache: boolean) => {
  console.log(`Processing: ${value}`)
  return value.toUpperCase()
})

// 根据条件决定是否使用缓存
console.log(conditionalMemo('hello', true))  // 计算并缓存
console.log(conditionalMemo('hello', true))  // 从缓存返回
console.log(conditionalMemo('hello', false)) // 计算(不同的参数)

缓存清理

typescript
import { memo } from 'radash'

const cachedFunction = memo((input: string) => {
  console.log(`Processing: ${input}`)
  return input.length
}, { maxSize: 2 })

console.log(cachedFunction('hello')) // 计算
console.log(cachedFunction('world')) // 计算
console.log(cachedFunction('test'))  // 计算,会清除'hello'的缓存
console.log(cachedFunction('hello')) // 重新计算

性能优化示例

typescript
import { memo } from 'radash'

// 模拟昂贵的计算
const expensiveOperation = memo((data: number[]) => {
  console.log('Performing expensive operation...')
  
  // 模拟耗时计算
  let result = 0
  for (let i = 0; i < 1000000; i++) {
    result += data.reduce((sum, num) => sum + num, 0)
  }
  
  return result
})

const data1 = [1, 2, 3, 4, 5]
const data2 = [6, 7, 8, 9, 10]

console.time('First call')
console.log(expensiveOperation(data1))
console.timeEnd('First call')

console.time('Cached call')
console.log(expensiveOperation(data1))
console.timeEnd('Cached call')

console.time('New data call')
console.log(expensiveOperation(data2))
console.timeEnd('New data call')

错误处理

typescript
import { memo } from 'radash'

const riskyFunction = memo((input: string) => {
  console.log(`Processing: ${input}`)
  
  if (input === 'error') {
    throw new Error('Simulated error')
  }
  
  return input.toUpperCase()
})

try {
  console.log(riskyFunction('hello')) // 正常工作
  console.log(riskyFunction('hello')) // 从缓存返回
  console.log(riskyFunction('error')) // 抛出错误
} catch (error) {
  console.error('Error:', error.message)
}

注意事项

  1. 内存使用: 缓存会占用内存,注意设置合适的maxSize
  2. 参数比较: 使用严格相等比较参数
  3. 异步函数: 支持异步函数,但缓存的是Promise
  4. 副作用: 避免在记忆化函数中使用副作用
  5. 缓存失效: 使用ttl可以设置缓存过期时间

与其他方法的区别

  • memo(): radash提供的记忆化工具
  • 手动缓存: 需要自己实现缓存逻辑
  • useMemo(): React Hook,仅用于组件内

实际应用场景

  1. 数学计算: 缓存昂贵的数学运算
  2. API调用: 缓存API响应
  3. 数据处理: 缓存数据处理结果
  4. 递归函数: 优化递归算法性能
  5. 配置处理: 缓存配置计算结果

Released under the MIT License.