手写一个 LRU
缓存函数
百度百科解释:
LRU
:Least Recently Used
的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
LRU Cache
通俗来讲,即”最不重要的且最不经常使用的数据,应优先删除“(内存空间是有限的)。
常见例子:
- 当用户访问不同站点,浏览器会缓存对应站点的一些信息,在下次访问同一站点,直接从缓存中获取,就可以实现使访问速度变快
- 浏览器的最近浏览记录存储
例子实现:
实现浏览器最近浏览记录的存储
需要注意的点:
-
访问内存中已存在的网址,需要重新更新该网址在内存中的存储顺序?
- 需要
-
没有数据的时候是否需要执行删除操作?
- 不需要而且不用担心(后面会解释)
-
内置方法应该用哪种:
put
,post
,delete
,get
?-
put
通常用于修改数据,该请求向服务器端发送数据,从而改变信息,就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。(当然,你也可以尝试一下拿put
来创建数据)post
通常用于创建数据,与put
的区别:POST
主要作用在一个集合资源之上的(url(统一资源定位符)),而PUT主要作用在一个具体资源之上的(url/xxx),通俗一下讲就是,如URL可以在客户端确定,那么可使用PUT
,否则用POST
。delete
通常用于删除数据get
通常用于获取数据(通常是幂等性 ==> 多次执行而不会改变系统状态(不会对数据进行修改),确保改变网站的一致性)
- 为了保证规范性,实现浏览器最近浏览记录的存储 中获取 URL 可以用
GET
,修改 URL 可以用PUT
-
需求分析:
- 数据往内存的插入或使用顺序应该是有序的 (不用
Object
)- 性能问题,即用O(1)时间复杂度实现缓存的读取,即不能去遍历所有数据(排除
Array
)- 数据的重复性?(不用
Set
)
排除 Object
,因为 Object
遍历 key
值时,是无序的(symbol
会按插入先后的顺序,而string
和number
会按ASCII
码大小 ...)
所以用
ES6
的 Map
来实现,Map
的特性:新插入的数据排在后面,旧数据放在前面,则:
-
删除数据,则优先从前面删除
-
读取数据,需要把该数据放在后面变成常用的数据
- 可以通过先删除该数据,然后在添加该数据实现
代码实现
初始化缓存函数:
class LRUCache {
constructor(n) {
this.size = n // 初始化最大缓存数据条为n
this.cacheMap = new Map() // 初始化缓存空间map
},
put(domain, info) {},
get(domain) {}
}
- 要注意的是,如果URL已存在,先移除数据,再更新数据,需遵守最大值不超过 n 的规则
最终实现:
class LRUCache {
constructor(n) {
this.size = n // 初始化最大缓存数据条为n
this.cacheMap = new Map() // 初始化缓存空间map
}
put(domain, info) {
if(this.cacheMap.has(domain)) {
// 已存在需更新数据的位置
this.cacheMap.delete(domain); //移除数据
}
if(this.cacheMap.size >= this.size) {
// 删除最不常用数据(Map.keys()返回一个迭代器 function* )
const firstKey = this.cacheMap.keys().next().value; // 不必当心cacheMap为空,因为this.size一般不为空
// [...this.cacheMap.keys()][0] // 写法2
this.cacheMap.delete(firstKey);
}
this.cacheMap.set(domain, info); // 在末尾重新插入数据
}
get(domain) {
if(!this.cacheMap.has(domain)) return false;
const info = this.cacheMap.get(domain); // 获取结果
this.cacheMap.delete(domain); // 移除数据
this.cacheMap.set(domain, info); // 在末尾重新插入数据
return info;
}
}