likes
comments
collection
share

lru-cache 库不完全指南

作者站长头像
站长
· 阅读数 2

该库提供了 lru 的具体实现,从版本7开始,这是JavaScript中性能最高的LRU实现之一,并支持多种多样的用例。

  // 'max'、'ttl'、'maxSize' 三个参数必须填写至少一个
const options = {
  max: 500,
}

const cache = new LRUCache(options)

cache.set('key', 'value')
cache.get('key') // "value"

class LRUCache<K, V, FC = unknown>(options)

  • K, V 为 键 值 的数据类型
  • FC 为 async fetch() 的接受的 context 参数类型

Options 配置

max (只读)

缓存中保留的最大项目数量。设置最大值可以防止缓存无界增长。

ttl

元素的最大存活时间,当存活时间到时可能不会立即被删除,即使从链表中删除,可能不会立即被垃圾回收机制进行内存的回收。

maxSize (只读)

缓存中保留的所有项目所占空间的最大值

maxEntrySize

每一项元素所占空间的最大值,超过这个大小的元素无法添加的缓存中。

sizeCalculation

用于计算所有传入的元素的大小的函数,可以覆盖掉 lru-cache 内部的计算函数。

fetchMethod(key, staleValue, { signal, options, context }) (只读)

进行异步操作,返回 promise

const c = new LRUCache({
  ttl: 100,
  ignoreFetchAbort: true, // true 时会忽略传递给 fetchMethod 的 AbortSignal 对象发出的中止事件,除非 signal 未定义,否则仍然会对结果进行缓存。
  allowStaleOnFetchAbort: true, // 当传递给 fetchMethod 的 AbortSignal 触发 “abort” 事件时,设置为 true 可以从缓存中返回一个过期的值。
  fetchMethod: async (key, oldValue, { signal }) => {
    // 不要将 signal 作为参数传递给 fetch 函数
    const res = await fetch(`https://slow-backend-server/${key}`)
    return await res.json()
  },
})

// 会在 100 毫秒后返回过期的值,并进行值的更新。
const val = await c.fetch('key', { signal: AbortSignal.timeout(100) })

dispose(value, key, reason) (只读)

当元素从缓存中删除时调用的函数。

原因为下列字符串之一:

  • evict: 为添加的元素倒空间
  • set: 元素被覆盖
  • delete: 使用 cache.delete(key) 或 cache.clear() 删除了该元素

ttlResolution

检查过期的元素的时间间隔. 默认值为 1,意味着每毫秒会检查一遍列表,确保没有过期的元素。设置为较高的值会提升性能。

ttlAutopurge

是否立即删除过期的元素,这可能会显著降低性能,特别是当缓存存储大量项目时。

updateAgeOnGet

当调用 get 方法时会将元素的存活时间重置,让元素不会过期。但不保证其他方式不会将元素删除。

API

set(key, value, [{ size, sizeCalculation, ttl, noDisposeOnSet, start, status }])

向缓存添加一个值。

可选选项对象可能包含如上所述的 ttl 和 sizeCalculation,默认为缓存对象上的设置。

get(key, { updateAgeOnGet, allowStale, status } = {}) => value

从缓存中获取值

async fetch(key, options = {}) => Promise

options 包含下列属性

  • updateAgeOnGet
  • allowStale
  • size
  • sizeCalculation
  • ttl
  • noDisposeOnSet
  • forceRefresh
  • status
  • signal
  • context

peek(key, { allowStale } = {}) => value

类似于 get(),但不会更新最近或删除过期的元素。 如果元素过期,则返回 undefined,除非在缓存或选项对象中设置 allowStale。

has(key, { updateAgeOnHas, status } = {}) => Boolean

检查缓存中是否存在对应元素

delete(key)

从缓存中删除对应元素

clear()

清空缓存

keys()

返回一个所有 keys 的 generator,从最多使用到最近使用。

rkeys()

返回一个所有 keys 的 generator,从最近使用到最多使用,刚好和keys相反。

values()

返回一个所有 values 的 generator,从最多使用到最近使用。

rvalues()

返回一个所有 values 的 generator,从最近使用到最多使用,刚好和 values 相反。

entries()

返回一个所有 键值对 的 generator, 从最多使用到最近使用。

rentries()

返回一个所有 键值对 的 generator, 从最近使用到最多使用,与 entries 相反。

find(fn, [getOptions])

类似于 Array.find() 返回符合条件的值。

LRU 是什么

lru-cache 库不完全指南

LRU是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。最近使用最少(LRU)缓存按使用顺序组织项目,可以快速识别哪个项目在最长时间内没有使用过。

一个应用场景是当B端用户读取页面时,需要从磁盘读取静态文件而后通过http/https进行请求的响应,而每次请求到来时若都去磁盘进行读取,速度是很慢的,如果在读取一次之后将需要响应的文件添加到内存中,下一次读取时相应速率会发生质的提升,因此有了 lru 。这也引申出一个问题,如果缓存较小或需要缓存的文件很大,需要怎么处理?

优点:

  • 超快速访问。LRU缓存按最近使用到最后使用的顺序存储项目。时间复杂度为 O(1)。
  • 超快的更新。每次访问项目时,更新缓存都需要 O(1)。

缺点:

  • 占用空间较大。LRU缓存 存储 n 项元素时 同时 需要长度为 n 的链表以及容量为 n 的 hashmap,空间复杂度O(n)