前言

【一天一个小知识,每天进步一点点】小伙伴们大家好。上一篇文章Vue2.0源码解析 - 知其然知其所以然之keep-alive原理分析(一)中已经对keep-alive源码的整体框架了做了一个简单的梳理,知道了keep-alive工作的一个大体流程,今天我们我将继续对keep-alive一些核心的源码进行展开分析。

cacheVNode

上篇文章中提到了在methods中定义了一个cacheVNode函数,用来做虚拟DOM的缓存,下面就来分析一下它的源码:

methods:{cacheVNode(){const {cache, keys, vnodeToCache, keyToCache} = this, if (vnodeToCache){const {tag, componentInstance, componentOptions } = vnodeToCachecache[keyToCache] = {name: getComponentName(componentOptions),tag,componentInstance,}keys.push(keyToCache)if(this.max && keys.length > parseInt(this.max)){pruneCacheEntry(cache, keys[0], keys, this._vnode)}this.vnodeToCache = null;}}
}
  • 首先获取实例上的四个属性cache, keys, vnodeToCache, keyToCache

    • 前两个属性已经在上一篇文章中有说明,这里不再赘述
    • vnodeToCache需要被缓存的虚拟dom
    • keyToCache需要被缓存的虚拟dom对应的key
  • 如果vnodeToCache不为空则说明需要被缓存,结构出vnodeToCache的详细信息,并保存在以keyToCache为键的对象cache中
  • 同时将键keyToCache保存在keys列表中
  • 判断是否设置了缓存最大值,如果设置了并且缓存列表的长度已经超过了最大值,则执行pruneCacheEntry函数对缓存列表进行修剪,注意这里是将最早缓存的组件进行删除。
  • 最后将vnodeToCache 清空

getComponentName

组件的公共函数,用于获取组件的名称

function getComponentName(opts: ?VNodeComponentOptions): ?string {return opts && (opts.Ctor.options.name || opts.tag);
}

pruneCacheEntry

组件的公共函数

function pruneCacheEntry (cache: VNodeCache,key: string,keys: Array<string>,current?: VNode
) {const cached = cache[key]// cached 有值,并且 不是当前正在渲染的 组件if (cached && (!current || cached.tag !== current.tag)) {cached.componentInstance.$destroy()}cache[key] = nullremove(keys, key)
}
  • 从cache对象中获取到要被销毁的组件实例
  • 如果存在并且不是当前正在渲染的组,则直接销毁
  • 同时从cache对象中移除虚拟dom实例
  • 从keys列表中移除对应的key

render

  render () {const slot = this.$slots.default//获取kepp-alive组件下的第一个子组件vndoeconst vnode: VNode = getFirstComponentChild(slot)const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptionsif (componentOptions) {// 获取组件名称const name: ?string = getComponentName(componentOptions)const { include, exclude } = this;//判断是否是需要缓存、不需要直接走这ifif (// 有include和没有获取到name值 或者 include是否包含name值(include && (!name || !matches(include, name))) ||// 是否是白名单、直接过滤(exclude && name && matches(exclude, name))) {return vnode}//需要缓存逻辑const { cache, keys } = this//判断是否有key、如果没有vue会自动给他加上keyconst key: ?string = vnode.key == null? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : ''): vnode.key//当前是否已经有缓存下来的组件数据、有直接取缓存的if (cache[key]) {//赋值缓存的vnodevnode.componentInstance = cache[key].componentInstance// make current key freshestremove(keys, key)keys.push(key)} else {// delay setting the cache until updatethis.vnodeToCache = vnodethis.keyToCache = key}//添加keepAlive = true标记vnode.data.keepAlive = true}return vnode || (slot && slot[0])}
  • 拿到keep-alive组件中的默认插槽,并根据插槽内容获取到keep-alive的第一个组件。前面的文章也提到过,即便是由多个子组件,默认也只有第一个是有效的。
  • 获取到子组件的名字name,并根据keep-alive的include和exclude去判断当前子组件是否被缓存,出现以下两种情况则不走缓存,直接将vnode返回
    • include:如果include属性存在,并且name不包含在include中
    • exclude:如果include属性存在,并且那么包含在exc中
  • 如果都不符合上述两种条件,则说明需要走缓存逻辑并从当前keep-alive实例中取出缓存对象cache和对应的键列表keys
  • 取出vnode的key,如果key不存在则重新生成一个
  • 根据key到cache对象中判断要被渲染的子组件是否被缓存
    • 如果cache对象中存在该子组件的缓存,则直接取出缓存对象的componentInstance(子组件实例)并赋值给vnode的componentInstance;同时将key从keys列表中移除并重新添加(为了保证当前key是最新的)
    • 如果子组件没有被缓存,则把vnode和key分别赋值给keep-alive实例的vnodeToCache和keyToCache两个属性中,等待下次更新时进行缓存
  • 最后设置keepAlive属性为true,并将当前vnode返回渲染。

总结

关于keep-alive的原理分析到这里就结束了。简单的总结下:就是在使用keep-alive时,会根据include和exclude两个属性来判断,keep-alive内部的子组件是否满足匹配条件,如果满足则把子组件对应的虚拟dom的实例利用cache和keys两个属性进行缓存。当下次子组件被重新渲染时首先判断缓存列表中是否存在,如果存在则直接从缓存中拉取,否则暂存在待缓存对象中待下次更新时缓存。
喜欢的小伙伴欢迎点赞留言加关注哦!

Vue2.0源码解析 - 知其然知其所以然之keep-alive原理分析(二)相关推荐

  1. Vue2.0源码解析——编译原理

    Vue2.0源码解析--编译原理 前言:本篇文章主要对Vue2.0源码的编译原理进行一个粗浅的分析,其中涉及到正则.高阶函数等知识点,对js的考察是非常的深的,因此我们来好好啃一下这个编译原理的部分. ...

  2. Vue2.0源码解析 - 知其然知其所以然之Vue.use

    前言 小伙伴们大家好.用过Vue的小伙伴都知道,在我们进行Vue开发时,避免不了会使用一些第三方的库,比如说ElementUI组件库.当我们导入好这些组件库后会执行一个Vue.use函数,然后把导进来 ...

  3. vue2.0源码解析(一)

    1.先下载vue源码(当前版本为:2.6.11) 地址: git clone https://github.com/vuejs/vue.git 2.切换到package.json dev脚本中 -c ...

  4. Vue2.0源码解析 - 知其然知其所以然之keep-alive

    前言 [一天一个小知识,每天进步一点点]小伙伴们大家好,今天将要给大家分享是Vue中关于组件缓存的一个内置组件 - keep-alive 不知道小伙伴们有没有遇到这样一种情况,在我们的项目开发中,有时 ...

  5. 锚框、交并比和非极大值抑制(tf2.0源码解析)

    锚框.交并比和非极大值抑制(tf2.0源码解析) 文章目录 锚框.交并比和非极大值抑制(tf2.0源码解析) 一.锚框生成 1.锚框的宽高 2.锚框的个数 3.注意点(★★★) 4.tf2.0代码 二 ...

  6. 前端进阶-手写Vue2.0源码(三)|技术点评

    前言 今天是个特别的日子 祝各位女神女神节快乐哈 封面我就放一张杀殿的帅照表达我的祝福 哈哈 此篇主要手写 Vue2.0 源码-初始渲染原理 上一篇咱们主要介绍了 Vue 模板编译原理 它是 Vue ...

  7. solrlucene3.6.0源码解析(三)

    solr索引操作(包括新增 更新 删除 提交 合并等)相关UML图如下 从上面的类图我们可以发现,其中体现了工厂方法模式及责任链模式的运用 UpdateRequestProcessor相当于责任链模式 ...

  8. Heritrix 3.1.0 源码解析(八)

    本文接着分析存储CrawlURI curi的队列容器,最重要的是BdbWorkQueue类及BdbMultipleWorkQueues类 BdbWorkQueue类继承自抽象类WorkQueue,抽象 ...

  9. Heritrix 3.1.0 源码解析(六)

    本文分析BdbFrontier对象的相关状态和方法 BdbFrontier类继承自WorkQueueFrontier类   WorkQueueFrontier类继承自AbstractFrontier类 ...

  10. Heritrix 3.1.0 源码解析(十一)

    上文分析了Heritrix3.1.0系统是怎么添加CrawlURI curi对象的,那么在系统初始化的时候,是怎么载入CrawlURI curi种子的呢? 我们回顾前面的文章,在我们执行采集任务的la ...

最新文章

  1. 量子计算时代更近了,未来可解决大规模计算的科学难题
  2. Binder相关面试总结(五):为什么Activity间传递对象需要序列化
  3. springMVC通过ajax传递参数list对象或传递数组对象到后台
  4. 多进程和多线程的概念
  5. 0330 第九次课:软件包安装及卸载
  6. 如何优雅地在公众号输入数学公式?推荐几款神器
  7. yarn资源管理调度平台
  8. springboot整合shiro+mybatis-plus
  9. Parsing Netflow using Kibana via Logstash to ElasticSearch
  10. 用计算机进行有理数除法时,有理数的乘除法怎么算?,什么是有理数的乘除法。越详细越好。...
  11. 关于java AudioInputStream播放短音频没声音的问题
  12. 怎么样生成bean对象java_使用BeanFactory实现创建对象
  13. axis2远程调用webservice例子(返回xml用dom4j解析)
  14. 70道经典Android面试题加答案--重要知识点几乎都涉及到了
  15. oracle 变长数组,oracle:变长数组varray,嵌套表,集合
  16. poj 1287 Networking (最小生成树Kruskal算法)
  17. vba九九乘法表代码_VBA程序控制结构示例-九九乘法表
  18. 【Proteus仿真】NE555延时电路
  19. mysql innodb_data_file_path_应急预案:专有云V3环境中RDS MySQL5.7实例修改innodb_temp_data_file_path参数的方法...
  20. 计算机管理内存条,win10系统查看电脑内存条型号的方法

热门文章

  1. 总结 部署 Kubernetes+Heapster+InfluxDB+Grafana 详解
  2. 关于微信小程序web开发者工具模拟器出现空白问题
  3. 【数字信号处理】离散时间信号 ( 离散时间信号 与 连续时间信号 关系 | 序列表示法 | 列表法 | 函数表示法 | 图示法 )
  4. ai的预览模式切换_ai预览快捷键是什么,Adobe Illustrator预览快捷键是什么?
  5. 2017年第八届CSTQB®国际软件测试高峰论坛议题征集启动
  6. 数据库三范式和BCNF范式的理解:生动举例
  7. java进销存管理系统设计_java进销存管理系统的设计与实现-springboot源码
  8. 3D游戏案例:滚动天空(超低配版)
  9. 数学建模一:层次分析法 附代码详解
  10. 一键批量修改文件夹名称