使用

<!-- 基本 -->
<keep-alive>
<component :is="view"></component>
</keep-alive>

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

当组件在 <keep-alive> 内被切换,它的 activateddeactivated 这两个生命周期钩子函数将会被对应执行。

原理

/* keep-alive组件 */
export default {
name: 'keep-alive',
/* 抽象组件 */
abstract: true, props: {
include: patternTypes,
exclude: patternTypes
}, created () {
/* 缓存对象 */
this.cache = Object.create(null)
}, /* destroyed钩子中销毁所有cache中的组件实例 */
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache[key])
}
}, watch: {
/* 监视include以及exclude,在被修改的时候对cache进行修正 */
include (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => matches(val, name))
},
exclude (val: string | RegExp) {
pruneCache(this.cache, this._vnode, name => !matches(val, name))
}
}, render () {
/* 得到slot插槽中的第一个组件 */
const vnode: VNode = getFirstComponentChild(this.$slots.default) const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
/* 获取组件名称,优先获取组件的name字段,否则是组件的tag */
const name: ?string = getComponentName(componentOptions)
/* name不在inlcude中或者在exlude中则直接返回vnode(没有取缓存) */
if (name && (
(this.include && !matches(this.include, name)) ||
(this.exclude && matches(this.exclude, name))
)) {
return vnode
}
const key: ?string = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
/* 如果已经做过缓存了则直接从缓存中获取组件实例给vnode,还未缓存过则进行缓存 */
if (this.cache[key]) {
vnode.componentInstance = this.cache[key].componentInstance
// 2.5.0 新增这段逻辑,使用 LRU 策略 make current key freshest
remove(keys, key);
keys.push(key);
}
// 不命中缓存,把 vnode 设置进缓存
else {
this.cache[key] = vnode;
// 2.5.0 新增这段逻辑,LRU 策略的移除。
keys.push(key);
// 如果配置了 max 并且缓存的长度超过了 this.max,还要从缓存中删除第一个
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode);
} }
/* keepAlive标记位 */
vnode.data.keepAlive = true
}
return vnode
}
}
  1. 获取 keep-alive 包裹着的第一个子组件对象及其组件名

    根据设定的 include/exclude(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例
  2. 根据组件 ID 和 tag 生成缓存 Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该 key 在 this.keys 中的位置(更新 key 的位置是实现 LRU 置换策略的关键)
  3. 在 this.cache 对象中存储该组件实例并保存 key 值,之后检查缓存的实例数量是否超过 max 的设置值,超过则根据 LRU 置换策略删除最近最久未使用的实例(即是下标为 0 的那个 key)
  4. 最后组件实例的 keepAlive 属性设置为 true,这个在渲染和执行被包裹组件的钩子函数会用到,

LRU 策略

最近最久未使用算法。

每次从内存中找出最久的未使用数据用于置换新的数据。

vue keep-alive的实现原理和缓存策略的更多相关文章

  1. vue 2.0 路由切换以及组件缓存源代码重点难点分析

    摘要 关于vue 2.0源代码分析,已经有不少文档分析功能代码段比如watcher,history,vnode等,但没有一个是分析重点难点的,没有一个是分析大命题的,比如执行router.push之后 ...

  2. 转 vue实现双向数据绑定之原理及实现篇

    转自:https://www.cnblogs.com/canfoo/p/6891868.html vue的双向绑定原理及实现 前言 先上个成果图来吸引各位: 代码:                  ...

  3. Vue数据绑定和响应式原理

    Vue数据绑定和响应式原理 当实例化一个Vue构造函数,会执行 Vue 的 init 方法,在 init 方法中主要执行三部分内容,一是初始化环境变量,而是处理 Vue 组件数据,三是解析挂载组件.以 ...

  4. vue我的总结+转原理

    我的总结 vue:1 mvvm模型,model,view,viewmodel,自底层向上,逐渐增加的模式2 .vue文件 包含html css js 有最近设计原则,将自己需要的放到最近,2 组件化 ...

  5. Vue双向绑定的实现原理系列(三):监听器Observer和订阅者Watcher

    监听器Observer和订阅者Watcher 实现简单版Vue的过程,主要实现{{}}.v-model和事件指令的功能 主要分为三个部分 github源码 1.数据监听器Observer,能够对数据对 ...

  6. vue实现双向数据绑定的原理

    vue实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的. 在MDN上对该方法的说明是:O ...

  7. 梳理vue双向绑定的实现原理

    Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后 ...

  8. vue的双向数据绑定实现原理

    在目前的前端面试中,vue的双向数据绑定已经成为了一个非常容易考到的点,即使不能当场写出来,至少也要能说出原理.本篇文章中我将会仿照vue写一个双向数据绑定的实例,名字就叫myVue吧.结合注释,希望 ...

  9. MySql 缓存查询原理与缓存监控 和 索引监控

    MySql缓存查询原理与缓存监控 And 索引监控 by:授客 QQ:1033553122 查询缓存 1.查询缓存操作原理 mysql执行查询语句之前,把查询语句同查询缓存中的语句进行比较,且是按字节 ...

随机推荐

  1. 基于 Spring Security 的前后端分离的权限控制系统

    话不多说,入正题.一个简单的权限控制系统需要考虑的问题如下: 权限如何加载 权限匹配规则 登录 1.  引入maven依赖 1 <?xml version="1.0" enc ...

  2. Huawei USG6530防火墙

    CF卡:(Compact Flash)最初是一种用于便携式电子设备的数据存储设备.作为一种存储设备,它革命性的使用了闪存 与sd卡的区别:SD卡的优点是安全.体积小巧,价格较之CF卡相对比较低,适合用 ...

  3. 使用 vite 构建一个表情选择插件

    初始化 Vite 基于原生 ES 模块提供了丰富的内建功能,开箱即用.同时,插件足够简单,它不需要任何运行时依赖,只需要安装 vite (用于开发与构建)和 sass (用于开发环境编译 .scss ...

  4. Unity 不能添加脚本组件,脚本类可能丢失

    报错: 把脚本拖到游戏对象,显示如下 原因: 你可能修改了脚本名称,但此时Unity没有找到那个对应脚本名称的类

  5. 乘风破浪,.Net Core遇见Dapr,为云原生而生的分布式应用运行时

    Dapr是一个由微软主导的云原生开源项目,国内云计算巨头阿里云也积极参与其中,2019年10月首次发布,到今年2月正式发布V1.0版本.在不到一年半的时间内,github star数达到了1.2万,超 ...

  6. 66.QT-线程并发、QTcpServer并发、QThreadPool线程池

    1.线程并发一个程序内部能拥有多个线程并行执行.一个线程的执行可以被认为是一个CPU在执行该程序.当一个程序运行在多线程下,就好像有多个CPU在同时执行该程序.总之,多线程即可以这么理解:多线程是处理 ...

  7. CRM系统什么时候需要使用

    CRM客户关系管理系统,相信每个人都会有所了解.现如今随着企业的发展需求,CRM软件已经成为了企业管理的刚需.无论是何种行业和规模的企业,客户都是最重要的资源,提高客户满意度也是企业的首要任务.如果您 ...

  8. JavaScript基础以及进阶知识

    JavaScript基础知识回顾: 目录: 比较运算符 多行字符串,模板字符串 严格模式 函数定义和调用 变量作用域与解构赋值.NameSpace.块级作用域let.const 方法 高阶函数 闭包 ...

  9. ExtJs4学习(五)最基本的Ext类

    Ext类是ExtJs中最常见.最基础的一个类,它是一个全局对象,封装了所有类.单例和 Sencha 库所提供的实用方法. 大多数用户界面组件在一个较低的层次嵌套在命名空间中, 但是提供的许多常见的实用 ...

  10. redis的基本操作指令

    https://www.cnblogs.com/woshimrf/p/5198361.html