缓存是写代码过程中常用的方法,是一种用空间换取时间的做法。就拿我们经常使用的HTTP协议来说,其中也有两种缓存方式:强缓存和协商缓存。当我们打开一个网站时,浏览器会查询请求的响应头,通过判断响应头中是否有Cache-Control、Last-Modified、ETag等字段来决定是否直接使用之前下载的资源缓存。重新开始从服务器下载。下面是我们访问百度时,有的资源命中协商缓存,服务器返回304状态码,有的资源命中强缓存,直接读取本地缓存。但是,缓存不是无限的,会有大小限制。不管是我们的cookie(不同浏览器不同,一般4KB左右),还是localStorage(和cookie一样,不同浏览器不同,有的浏览器5MB,有的浏览器10MB),都会有大小限制。这时候就需要涉及到一个算法,需要淘汰超过大小限制的缓存。总的规则是淘汰最近没有访问过的缓存,也就是今天要介绍的主角:LRU(Leastrecentlyused:最近最少使用)use)。当然,除了LRU,常见的缓存淘汰还有FIFO(first-in,first-out:先进先出)和LFU(Leastfrequentlyused:最少使用)。什么是LRU?当缓存满时,LRU(Leastrecentlyused)算法会根据所有数据的访问记录,剔除未来被访问概率最低的数据。也就是说,算法认为最近被访问过的数据,未来被访问的概率最大。为了便于理解LRU算法的整个过程,画了一个简单的图:假设我们有一块内存,总共可以存放5个数据块;将A、B、C、D、E依次存入内存,此时内存已满;当再次插入新的数据时,在内存中保存时间最长的数据A将被淘汰;当我们再次从外部读取数据B时,已经在末尾的B会被标记为活跃并引用到头部,数据C成为存储时间最长的数据;如果再次插入新的数据G,则淘汰存储时间最长的数据C;算法实现使用一个简单的代码来实现这个逻辑。classLRUCache{list=[]//用于标记顺序cache={}//用于缓存所有数据capacity=0//缓存构造函数的最大容量(capacity){//存储最大可以缓存的容量通过LRU缓存this。capacity=capacity}}基本结构如上所示,LRU需要实现的是两个方法:get和put。classLRUCache{//获取数据get(key){}//存储数据put(key,value){}}现在让我们看看如何存储数据:classLRUCache{//存储数据put(key,value){//存储前需要判断长度是否达到上限if(this.list.length>=this.capacity){//每次存储后,key都会被放到链表的尾部,//因此,第一个需要取出key,删除缓存中的数据。constlatest=this.list.shift()deletethis.cache[latest]}//写入缓存this.cache[key]=value//写入缓存后,需要将key放入最后一个列表this.list。push(key)}}然后,每次取数据时,需要更新列表,将当前取的key放在列表的末尾。classLRUCache{//获取数据get(key){if(this.cache[key]!==undefined){//如果key对应的缓存存在//返回缓存前需要重新激活keythis.active(key)returnthis.cache[key]}returnundefined}//重新激活key,将指定的key移动到列表中Finallyactive(key){//先从列表中删除keyconstidx=this.list.indexOf(key)if(idx!==-1){this.list.splice(idx,1)}//然后把key放到list的最后this.list.push(key)}}at这一次,它还没有完全实现。因为除了get操作,put操作还需要重新激活相应的key。classLRUCache{//存储数据put(key,value){if(this.cache[key]){//如果key之前存在,重新激活keythis.active(key)this.cache[key]=value//并且此时缓存的长度不会发生变化//所以不需要进行后续的长度判断,可以直接返回}//入库前需要判断长度是否达到上限if(this.list.length>=this.capacity){//每次存储后,key都会放在链表的末尾,//因此需要取出第一个key,删除缓存中的数据.constlatest=this.list.shift()deletethis.cache[latest]}//写入缓存this.cache[key]=value//写入缓存后,需要将key放入最后一个列表this.list。push(key)}}可能有人认为这个算法在前端没有应用场景。说到这里,Vue内置的组件keep-alive就是用到了LRU算法。后续应该会继续介绍LFU算法,敬请期待……
