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響應
- 數據處理: 緩存數據處理結果
- 遞歸函數: 優化遞歸算法性能
- 配置處理: 緩存配置計算結果