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)
}
注意事项
- 内存使用: 缓存会占用内存,注意设置合适的maxSize
- 参数比较: 使用严格相等比较参数
- 异步函数: 支持异步函数,但缓存的是Promise
- 副作用: 避免在记忆化函数中使用副作用
- 缓存失效: 使用ttl可以设置缓存过期时间
与其他方法的区别
memo()
: radash提供的记忆化工具- 手动缓存: 需要自己实现缓存逻辑
useMemo()
: React Hook,仅用于组件内
实际应用场景
- 数学计算: 缓存昂贵的数学运算
- API调用: 缓存API响应
- 数据处理: 缓存数据处理结果
- 递归函数: 优化递归算法性能
- 配置处理: 缓存配置计算结果