LRU缓存--keep-alive实现原理

155 阅读3分钟

前言

keep-alive组件大家一定不陌生,那什么是keep-alive呢?
keep-alive 是 Vue.js 的一个 内置组件。它能够将不活动的组件实例保存在内存中,而不是直接将其销毁,它是一个抽象组件,不会被渲染到真实 DOM 中,也不会出现在父组件链中。简单的说,keep-alive用于保存组件的渲染状态,避免组件反复创建和渲染,有效提升系统性能。 keep-alivemax 属性,用于限制可以缓存多少组件实例,一旦这个数字达到了上限,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉,而这里所运用到的缓存机制就是 LRU 算法

LRU算法

LRU( least recently used)根据数据的历史记录来淘汰数据,重点在于保护最近被访问/使用过的数据,淘汰现阶段最久未被访问的数据

LRU主体思想:如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。

image.png

它的大致顺序如下:
1.新的数据插入到链表尾部;
2.如果命中缓存即链表内数据被访问,将命中的缓存移动到链表尾部;
3.链表长度满,移除链表头部数据。

LRU简易实现

LRU算法一般是通过双向链表和hashmap来实现的。js没有提供链表数据结构,但是实现了Map,所以可以用class和Map来简易实现一下。

// LRU.js
export class LRUCache {
  cpacity; // 容量
  cache;
  constructor(cpacity) {
    this.cpacity = cpacity;
    this.cache = new Map();
  }
  get (key) {
    if (this.cache.has(key)) {
      let idx = this.cache.get(key);
      // 先删除原先的数,再添加到末尾
      this.cache.delete(key);
      this.cache.set(key, idx);
      return idx;
    }
    return -1
  }
  put (key, value) {
    if (this.cache.has(key)) this.cache.delete(key);
    else if (this.cache.size >= this.cpacity) this.cache.delete(this.cache.keys().next().value)
    this.cache.set(key, value);
  }
  toString () {
    console.log('capacity', this.cpacity)
    console.table(this.cache)
  }
}
// index.js
import { LRUCache } from './LRU算法.js'
const list = new LRUCache(4)
list.put(2, 2)   // 入 2,剩余容量3
list.put(3, 3)   // 入 3,剩余容量2
list.put(4, 4)   // 入 4,剩余容量1
list.put(5, 5)   // 入 5,已满    从头至尾         2-3-4-5
list.put(4, 4)   // 入4,已存在 ——> 置队尾         2-3-5-4
list.put(1, 1)   // 入1,不存在 ——> 删除队首 插入1  3-5-4-1
list.get(3)     // 获取3,刷新3——> 置队尾         5-4-1-3
list.toString()

image.png

keep-alive

vue将dom节点抽象成了VNode节点,通过cache对象将组件的vnode缓存起来。先将满足条件的include和exclude组件缓存起来,max定义容器容量,需要重新渲染的时候将组件的vnode从cache拿出来。
过程如下:

  1. 声明有序集合list,存储组件的唯一标识key;
  2. 函数执行渲染,如果命中缓存,从有序集合list中取出组件,在list中删除key值并重新插入到队尾;
  3. 如果没有命中缓存,list长度已经等于max,删除队首最不常用组件的key值,并将组件key插入到list当中;
  4. 触发beforeMount/beforeUpdate生命周期时,缓存activated状态的组件数据和渲染状态。

结语

写的不好,各位大佬多多指教,感恩家人🙏