5分钟学会 LRU 算法,浏览器历史记录的缓存原理,留着面试不香吗?

430 阅读2分钟

整日与浏览器打交道的前端老司机们,如果还不知道浏览器的历史记录是如何保存的,不妨花几分钟时间来了解下 LRU 算法,那么,

什么是 LRU 算法?

LRU(Least recently used,最近最少使用)是一种常用的页面置换算法LRU 算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

LRU 算法的使用场景

  1. 比如浏览器的历史记录缓存
  2. 缓存服务,比如 redis 缓存
  3. 用 hash 表作为底层结构的数据库

算法核心原理:有一块大小固定的内存,用于存放我们最近访问的页面。我们不断往内存中添加页面,当内存满了,需要删除内存中最早访问的页面,让新页面插入内存进行缓存。这样一个不断添加和删除网页的过程就是 LRU 算法。

Map 实现 LRU 算法

我们使用 SE6 Map 数据结构存储数据。Map 自带的 get、set、delete、has 方法能方便我们对数据进行增删改查操作。

实现思路: 1、首先定义一个类 LRUfunc ,我们设置一个最大长度 length,用来限制 map 的大小,模拟大小固定的内存。 2、然后,添加 get 方法,进行页面查询。做两件事:历史记录有页面时,先将该页面删除;再将页面插入到 map 的头部,表示最新访问了该页面。 3、再者,添加 set 方法,进行页面的添加处理。新增页面时,查询 map ,如果历史记录中该页面已存在,先把页面删除,再把页面放到 map 头部,表示最新访问。如果页面不存在时,先看 map 大小是否已经超出设定长度,超出长度限制时表示内存满了,我们需要先把 map 尾部的页面删除,然后将新增的页面插入到 map 的头部,表示最新访问了该页面。

话不多说,直接上代码:

/**
* 定义 LRUfunc 类存储数据,实现完成一个 LRU 缓存
*/
class LRUfunc {
    constructor(length){
        this.length = length
	this.map = new Map()
    }

    // 获取数据
    get(data) {
	if(!this.map.get(data)) return null
	this.map.delete(data)
	this.map.set(data,data)
    }

    // 设置数据
    set(data) {
	if(this.map.has(data)){
            // 如果内存中有页面,先把页面删除,再把页面放到内存最新位置
            this.map.delete(data)
	}

	if(this.map.size + 1 > this.length) {
            this.map.delete(this.map.keys().next().value)
	}

	this.map.set(data, data)
    }
}

const lru = new LRUfunc(3)
lru.set('zhangsan')
lru.set('lisi')
lru.set('wangwu')
console.log(lru)

向 map 添加 3 个页面,输出:

截屏2022-06-18 下午4.50.47.png

再访问新页面 lru.set(''newpage),map.size 依旧是 3 ,输出:

截屏2022-06-18 下午4.51.01.png

写在结尾:如果你觉得这篇文章对你有那么一咻咻点用处,不妨给个赞,你的支持和鼓励是我不断分享的动力!