vue源码解析之keep-alive原理

2,964 阅读4分钟

keep-alive是什么

keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

应用场景

用户在列表页输入一些查询条件,进入详情页面后再返回列表页面的时候,查询条件能够被缓存起来,效果图如下:

源码分析

props

<keep-alive :include="whiteList" :exclude="blackList" :max="amount">
  <router-view></router-view>
</keep-alive>
  1. include定义缓存白名单,keep-alive会缓存命中的组件;
  2. exclude定义缓存黑名单,被命中的组件将不会被缓存;
  3. max定义缓存组件上限,超出上限使用LRU的策略置换缓存数据;

created

created方法很简单,就初始化了两个变量

  1. cache用来缓存虚拟dom;
  2. keys用来缓存虚拟dom的键集合

mounted

在mounted这个钩子中对include和exclude参数进行监听,然后实时地更新(删除)this.cache对象数据。pruneCache函数的核心也是去调用pruneCacheEntry。

render

  1. 获取keep-alive包裹着的第一个子组件对象及其组件名;
  2. 根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(VNode),否则执行第三步;
  3. 根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键),否则执行第四步;
  4. 在this.cache对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max的设置值,超过则根据LRU置换策略删除最近最久未使用的实例(即是下标为0的那个key);
  5. 最后将该组件实例的keepAlive属性值设置为true;

destroyed

  1. this.cache中缓存的VNode实例;
  2. 遍历调用pruneCacheEntry函数删除缓存VNode还要对应执行组件实例的destory函数;

keep-alive组件的渲染

keep-alive不会生成真正的DOM节点,这是怎么做到的?

  1. vue在初始化生命周期的时候,为组件实例建立父子关系会根据abstract属性决定是否忽略某个组件。在keep-alive中,设置了abstract:true,那么Vue就会跳过该组件实例;
  2. 最后构建的组件树中就不会包含keep-alive组件,那么由组件树渲染成的DOM树自然也不会有keep-alive相关的节点了;

keep-alive包裹的组件是如何使用缓存的

  1. 在首次加载被包裹组件时,由keep-alive.js中的render函数可知,vnode.componentInstance的值是undefined,keepAlive的值是true,因为keep-alive组件作为父组件,它的render函数会先于被包裹组件执行;那么就只执行到i(vnode, false /* hydrating */),后面的逻辑不再执行;
  2. 再次访问被包裹组件时,vnode.componentInstance的值就是已经缓存的组件实例,那么会执行insert(parentElm, vnode.elm, refElm)逻辑,这样就直接把上一次的DOM插入到了父元素中;

部分钩子函数只执行一次

当vnode.componentInstance和keepAlive同时为true时,不再进入$mount过程,那mounted之前的所有钩子函数(beforeCreate、created、beforeMounted mounted)都不再执行。

activated和deactivated

activated是在keep-alive内组件加载成功后调用

deactivated是在keep-alive内组件缓存成功后调用

deactivated钩子函数也是一样的原理,在组件实例(VNode)的destroy钩子函数中调用deactivateChildComponent函数。

vue系列课程

最近会陆续的对vue进行源码分析,一系列课程如下:

state系列

  1. props原理
  2. methods原理
  3. data原理
  4. computed原理
  5. watch原理

lifecycle系列

  1. 生命周期原理

event系列

  1. event原理

render系列

  1. render原理

inject/provide系列

  1. inject/provide原理

plugins系列

  1. vue-router原理
  2. Vue Router 那些事
  3. Vuex你应该知道的事
  4. vue源码解析之vuex原理
  5. Vue自定义插件

组件系列

  1. keep-alive原理
  2. Vue 单文件组件
  3. Vue组件间通信
  4. vue虚拟列表

指令系列

  1. Vue自定义指令
  2. vue源码解析之Directives原理

算法系列

  1. diff原理
  2. Vue编译器源码分析

异步任务

  1. vue源码解析之NextTick原理

其他

  1. vue单元测试
  2. Vue轮播组件
  3. 你不知道的vue那些事
  4. vue技巧大解密
  5. 面试-高级前端之VUE数据响应式实现