缓存策略
常见的缓存策略有三种,FIFO(先进先出)、LFU(least frequently used)、LRU(least recently used)。
这里主要学习一下 LRU - 最近最少使用算法,因为浏览器的缓存策略以及 vue 的 keep-alive 都是使用的这种算法。
LRU
核心思想是:如果数据最近被访问过,那么将来被访问的⼏率也更⾼,优先淘汰最近没有被访问到的数据。
/**
* 数组 + 对象实现
*/
class LRUCache {
constructor(capacity) {
this.keys = [];
this.cache = {};
this.capacity = capacity;
}
get(key) {
if (!this.cache[key]) return -1;
// 下面两步调整位置
LRUCache.remove(this.keys, key);
this.keys.push(key);
return this.cache[key];
}
put(key, value) {
// 如果不存在直接存储,同时判断是否超出容量,超出就做处理
if (!this.cache[key]) {
this.cache[key] = value;
this.keys.push(key);
if (this.keys.length > this.capacity) {
LRUCache.removeCache(this.keys, this.cache, this.keys[0]);
}
} else {
// 如果已存在就删除之前的,放入最新的
this.cache[key] = value;
LRUCache.remove(this.keys, key);
this.keys.push(key);
}
}
static remove(keys, key) {
if (!keys.length) return;
const index = keys.findIndex(item => item == key) >>> 0;
keys.splice(index, 1);
}
static removeCache(keys, cache, key) {
cache[key] = null;
LRUCache.remove(keys, key);
}
}
进阶
利用Map自身就能存储键值对和顺序的特点,很容易实现。
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
// 存在即更新
if (this.cache.has(key)) {
const res = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, res);
return res;
}
return -1;
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
this.cache.delete(this.cache.keys().next().value);
}
this.cache.set(key, value);
}
}
/* -------------------------- test -------------------------- */
let cache = new LRUCache(2); // 设置容量为2
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 1被使用了
cache.put(3, 3); // 2被释放
cache.get(2); // -1