cachedAsync
为异步函数添加智能缓存,提升应用性能。
函数签名
typescript
function cachedAsync<T extends (...args: any[]) => Promise<any>>(
fn: T,
options?: CachedAsyncOptions
): CachedAsyncFunction<T>
interface CachedAsyncOptions {
keyGenerator?: (...args: any[]) => string
ttl?: number
maxSize?: number
cache?: LRUCache<string, any>
cacheErrors?: boolean
debug?: boolean
console?: { log: (...args: any[]) => void; warn: (...args: any[]) => void }
}
interface CachedAsyncFunction<T> {
(...args: Parameters<T>): ReturnType<T>
clear: () => void
delete: (...args: Parameters<T>) => void
has: (...args: Parameters<T>) => boolean
getStats: () => { size: number; hits: number; misses: number; hitRate: number }
}参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
fn | AsyncFunction | 是 | 需要缓存的异步函数 |
options.keyGenerator | Function | 否 | 缓存键生成函数,默认使用 JSON.stringify |
options.ttl | number | 否 | 缓存过期时间(毫秒),0表示永不过期 |
options.maxSize | number | 否 | 最大缓存容量,默认500 |
options.cache | LRUCache | 否 | 自定义缓存实例 |
options.cacheErrors | boolean | 否 | 是否缓存错误结果,默认false |
options.debug | boolean | 否 | 是否启用调试日志,默认false |
返回值
| 类型 | 说明 |
|---|---|
CachedAsyncFunction | 带缓存的异步函数,附带缓存管理方法 |
工作原理
- 首次调用:执行异步函数,缓存结果
- 缓存命中:直接返回缓存结果,不执行函数
- TTL 过期:缓存过期后重新执行函数
- LRU 清理:容量满时删除最少使用的缓存
- 防重复请求:并发相同请求共享 Promise
基础示例
typescript
import { cachedAsync } from 'zcw-shared/functions/async/cachedAsync'
// 创建带缓存的异步函数
const fetchUser = cachedAsync(
async (userId: string) => {
const response = await fetch(`/api/users/${userId}`)
return response.json()
},
{
ttl: 5000, // 5秒过期
maxSize: 100 // 最多100个
}
)
// 第一次调用 - 执行函数并缓存
const user1 = await fetchUser('user-123') // 发起网络请求
// 第二次调用 - 使用缓存
const user2 = await fetchUser('user-123') // 立即返回,无网络请求
// 5秒后缓存过期,再次调用会重新请求
await new Promise(r => setTimeout(r, 5000))
const user3 = await fetchUser('user-123') // 重新发起网络请求实际应用场景
API 请求缓存
typescript
// 用户信息请求
const fetchUser = cachedAsync(
async (userId: string) => {
const res = await fetch(`/api/users/${userId}`)
return res.json()
},
{ ttl: 60000 } // 1分钟缓存
)
// 文章列表请求
const fetchPosts = cachedAsync(
async (page: number, pageSize: number) => {
const res = await fetch(`/api/posts?page=${page}&size=${pageSize}`)
return res.json()
},
{ ttl: 30000 } // 30秒缓存
)
// 使用
app.get('/users/:id', async (req, res) => {
const user = await fetchUser(req.params.id)
res.json(user)
})数据库查询缓存
typescript
const getUserById = cachedAsync(
async (userId: string) => {
return await db.users.findOne({ id: userId })
},
{
ttl: 10000, // 10秒缓存
maxSize: 1000 // 最多缓存1000个用户
}
)
// 第一次查询数据库
const user1 = await getUserById('123')
// 后续查询使用缓存,不访问数据库
const user2 = await getUserById('123')共享缓存实例
typescript
import { LRUCache } from 'zcw-shared/functions/data-structures/LRUCache'
import { createCachedAsyncWithCache } from 'zcw-shared/functions/async/cachedAsync'
// 创建共享的缓存实例
const sharedCache = new LRUCache<string, any>({
capacity: 1000,
debug: true,
console: { log: console.log, warn: console.warn }
})
// 创建工厂函数
const createCachedFn = createCachedAsyncWithCache(sharedCache)
// 多个函数共享同一个缓存(注意键冲突)
const fetchUser = createCachedFn(
async (id: string) => fetch(`/api/users/${id}`).then(r => r.json()),
{ ttl: 60000, keyGenerator: (id) => `user:${id}` }
)
const fetchPost = createCachedFn(
async (id: string) => fetch(`/api/posts/${id}`).then(r => r.json()),
{ ttl: 30000, keyGenerator: (id) => `post:${id}` }
)防止重复请求
typescript
const fetchData = cachedAsync(
async (id: string) => {
// 模拟慢速 API
await new Promise(r => setTimeout(r, 2000))
return fetch(`/api/data/${id}`).then(r => r.json())
}
)
// 并发请求
const [result1, result2, result3] = await Promise.all([
fetchData('123'), // 发起请求
fetchData('123'), // 复用第一个请求的 Promise
fetchData('123') // 复用第一个请求的 Promise
])
// 只发起了1次网络请求
console.log(result1 === result2) // true自定义缓存键
typescript
// 复杂参数的缓存键生成
const searchProducts = cachedAsync(
async (query: string, filters: any, sort: string) => {
return fetch('/api/products/search', {
method: 'POST',
body: JSON.stringify({ query, filters, sort })
}).then(r => r.json())
},
{
keyGenerator: (query, filters, sort) => {
// 自定义键生成逻辑
return `search:${query}:${JSON.stringify(filters)}:${sort}`
}
}
)缓存管理
typescript
const fetchUser = cachedAsync(async (id) => { ... }, options)
// 清除所有缓存
fetchUser.clear()
// 删除特定缓存
fetchUser.delete('user-123')
// 检查缓存是否存在
if (fetchUser.has('user-123')) {
console.log('缓存存在')
}
// 获取统计信息
const stats = fetchUser.getStats()
console.log(stats)
// {
// size: 10, // 当前缓存数量
// hits: 100, // 命中次数
// misses: 20, // 未命中次数
// hitRate: 0.83 // 命中率 83%
// }错误处理
typescript
// 默认不缓存错误
const fetchUser = cachedAsync(async (id) => {
const res = await fetch(`/api/users/${id}`)
if (!res.ok) throw new Error('User not found')
return res.json()
})
try {
await fetchUser('invalid-id') // 抛出错误
} catch (e) {
// 错误不会被缓存
}
await fetchUser('invalid-id') // 再次请求,不使用缓存
// 启用错误缓存
const fetchUserWithErrorCache = cachedAsync(
async (id) => { ... },
{ cacheErrors: true, ttl: 5000 }
)
// 错误会被缓存5秒
try {
await fetchUserWithErrorCache('invalid-id')
} catch (e) {
// 错误被缓存
}
await fetchUserWithErrorCache('invalid-id') // 立即抛出缓存的错误带缓存的异步函数,轻松提升应用性能!