vue中keep-alive的实现以及LRU缓存策略
基本思路
- keep-alive要求只有一个子元素被渲染,所以一般搭配动态组件component或router-view使用。
因为我们是在keep-alive中开发,所以可以先获取默认插槽,然后获取他的第一个子元素和他的组件名,根据设置的include/exclude进行匹配,如果匹配到会走缓存,没有的话会直接返回组件实例。
- 命中缓存直接获取,同时更新key的位置
根据组件id和tag生成缓存key,并在缓存数组中查找此组件是否已经被缓存,如果命中,直接取出,同时更新key在缓存数组中的位置(更新位置是LRU缓存策略实现的关键)
- 如果没有命中就加入缓存,同时检查缓存的实例是否超过max
将组件实例加入cache数组,并存储key值,然后检查key数组的长度是否已经超过了最大值。如果超过了则会处理掉最久不用的实例
- 设置组件实例中data内的keepAlive标志位
abstract
与transition相似,keep-alive也是一个抽象组件,它本身不会渲染一个DOM元素,也不会出现在组件的父组件链中
组件一旦被缓存,重新渲染时的created,mounted等生命周期就不会执行,而是提供了activated和deactivated两个钩子
vue在初始化生命周期的时候,为组件实例建立父子关系的时候会根据abstract属性判断是否需要渲染某个组件,keep-alive中设置了abstract:true 所以渲染时会跳过这个组件实例
export function initLifecycle (vm: Component) {
const options = vm.$options
// locate first non-abstract parent
let parent = options.parent
if (parent && !options.abstract) {
while (parent.$options.abstract && parent.$parent) {
parent = parent.$parent
}
parent.$children.push(vm)
}
keep-alive的首次渲染和缓存渲染
首次渲染的时候,除了在<keep-alive>中建立缓存,设置vnode.data.keepAlive为true,其他过程和普通组件是一致的。
缓存渲染的时候,会根据vnode.componentInstance(首次渲染时为undefined)和vnode.data.keepAlive判断不再执行组件的created和mounted,直接对缓存的组件patch,最后直接把DOM插入到目标元素中,完成更新。
LRU(last recently used)缓存策略
核心思想为
如果数据最近被访问过,那以后访问这条数据的可能性就越高
最常见的实现是使用一个链表保存缓存数据,详细的实现如下:
- 新数据插入到链表头部
- 缓存命中时,将数据移动到链表头部
- 当链表达到最大值时,删除尾部数据
最后附上一道leetcode关于lru的题目