Discards the least recently used items first. This algorithm requires keeping track of what was used when, which is expensive if one wants to make sure the algorithm always discards the least recently used item. General implementations of this technique require keeping "age bits" for cache-lines and track the "Least Recently Used" cache-line based on age-bits. In such an implementation, every time a cache-line is used, the age of all other cache-lines changes.
在上图中,一旦 A B C D 充满所分配的内存块,那么最新出现的 E 将替代最低使用的 A(0)
,访问顺序为 A -> B -> C -> D -> E -> D -> F。javascript
这里将会出现一个性能瓶颈,也就是在 Cache 满时,淘汰那些不经常使用的数据,空出空间存储新的数据。假设每一条数据都有一个最后访问时间, 当满额的时候,将要遍历全部元素,才能删除访问时间最小的那个元素,时间复杂度为 $O(1)$,数据量越大,性能越低。java
因此选择使用 链表
,每访问一次数据,把最新的访问数据放至头部,那尾部的数据就是最旧未访问的数据。 满额时,从链表尾部开始往前删除指定数目的数据,便可解决。缓存
class LruCache { constructor(maxsize) { this._cache = {}; // 缓存 this._queue = []; // 队列 this._maxsize = maxsize; // 最大值 // 若是最大值输入非法 默认无限大 if (!this._maxsize || !(typeof this._maxsize === 'number') || this._maxsize <= 0) { this._maxsize = Infinity; } // 运行定时器,定时检查过时值 setInterval(() => { this._queue.forEach((el, idx) => { const key = el; const insertTime = this._cache[key].insertTime; const expire = this._cache[key].expire; const curTime = +new Date(); // 若是存在过时时间且超期,移除数据 if (expire && curTime - insertTime > expire) { this._queue.splice(idx--, 1); delete this._cache[key]; } }); }, 1000); } // 生成惟一索引 _makeSymbol(key) { return Symbol.for(key); } // 更新队列 _update(queue, key) { // 移除 queue.forEach((el, idx) => { if (el === key) { queue.splice(idx, 1); } }); // 前置 queue.unshift(key); return queue; } // 插入数据 set(key, value, expire) { key = this._makeSymbol(key); // 生成惟一索引 // 若是已经存在该值,则从新赋值 if (this._cache[key]) { this._cache[key] = { value, expire, insertTime: this._cache[key].insertTime } this._queue = this._update(this._queue, key); // 更新队列 } else { // 若是不存在,则插入 this._cache[key] = { value, expire, insertTime: +new Date() } // 索引置前 this._queue.unshift(key); // 超出最大值,截断 while (this._queue.length > this._maxsize) { const item = this._queue.pop(); // 尾截断 delete this._cache[item]; // 删除 } } } // 获取数据 get(key) { key = this._makeSymbol(key); // 若是存在该值 if (this._cache[key]) { const insertTime = this._cache[key].insertTime; // 插入时间 const expire = this._cache[key].expire; // 过时时间 const curTime = +new Date(); // 当前时间 // 若是不存在过时时间 或 存在过时时间但还没有过时 if (!expire || (expire && curTime - insertTime < expire)) { // 更新队列,前置索引 this._queue = this._update(this._queue, key); return this._cache[key].value; } else if (expire && curTime - insertTime > expire) { // 已通过期 this._queue.forEach((el, idx) => { if (el === key) { this._queue.slice(idx, 1); delete this._cache[key]; } }) return null } } else { return null; } } }
同步至个人我的博客:https://blog.trevor.top/item/34性能