keep-alive

基本属性

  • include 字符串或者正则表达式,只有名称匹配的组件会被匹配

  • exclude 字符串或者正则表达式,任何名称匹配的都不会别缓存

  • max 数字 最多缓存多少组件实例

     注意:  keep-alive 包裹动态组件时,会缓存不活动的组件实例。
    

主要流程

  1. 判断组件 name ,不在 include 或者在 exclude 中,直接返回 vnode,说明该组件不被缓存。
  2. 获取组件实例 key ,如果有获取实例的 key,否则重新生成。
  3. key生成规则,cid +“∶∶”+ tag ,仅靠cid是不够的,因为相同的构造函数可以注册为不同的本地组件。
  4. 如果缓存对象内存在,则直接从缓存对象中获取组件实例给 vnode ,不存在则添加到缓存对象中。
  5. 最大缓存数量,当缓存组件数量超过 max 值时,清除 keys 数组内第一个组件。

keep-alive 的实现

const patternTypes: Array<Function> = [String, RegExp, Array] // 接收:字符串,正则,数组export default {name: 'keep-alive',abstract: true, // 抽象组件,是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。props: {include: patternTypes, // 匹配的组件,缓存exclude: patternTypes, // 不去匹配的组件,不缓存max: [String, Number], // 缓存组件的最大实例数量, 由于缓存的是组件实例(vnode),数量过多的时候,会占用过多的内存,可以用max指定上限},created() {// 用于初始化缓存虚拟DOM数组和vnode的keythis.cache = Object.create(null)this.keys = []},destroyed() {// 销毁缓存cache的组件实例for (const key in this.cache) {pruneCacheEntry(this.cache, key, this.keys)}},mounted() {// prune 削减精简[v.]// 去监控include和exclude的改变,根据最新的include和exclude的内容,来实时削减缓存的组件的内容this.$watch('include', (val) => {pruneCache(this, (name) => matches(val, name))})this.$watch('exclude', (val) => {pruneCache(this, (name) => !matches(val, name))})},
}

render函数

  1. 会在 keep-alive 组件内部去写自己的内容,所以可以去获取默认 slot 的内容,然后根据这个去获取组件
  2. keep-alive 只对第一个组件有效,所以获取第一个子组件。
  3. keep-alive 搭配使用的一般有:动态组件 和router-view
render () {//function getFirstComponentChild (children: ?Array<VNode>): ?VNode {if (Array.isArray(children)) {for (let i = 0; i < children.length; i++) {const c = children[i]if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {return c}}}}const slot = this.$slots.default // 获取默认插槽const vnode: VNode = getFirstComponentChild(slot)// 获取第一个子组件const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions // 组件参数if (componentOptions) { // 是否有组件参数// check patternconst name: ?string = getComponentName(componentOptions) // 获取组件名const { include, exclude } = thisif (// not included(include && (!name || !matches(include, name))) ||// excluded(exclude && name && matches(exclude, name))) {// 如果不匹配当前组件的名字和include以及exclude// 那么直接返回组件的实例return vnode}const { cache, keys } = this// 获取这个组件的keyconst 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.keyif (cache[key]) {// LRU缓存策略执行vnode.componentInstance = cache[key].componentInstance // 组件初次渲染的时候componentInstance为undefined// make current key freshestremove(keys, key)keys.push(key)// 根据LRU缓存策略执行,将key从原来的位置移除,然后将这个key值放到最后面} else {// 在缓存列表里面没有的话,则加入,同时判断当前加入之后,是否超过了max所设定的范围,如果是,则去除// 使用时间间隔最长的一个cache[key] = vnodekeys.push(key)// prune oldest entryif (this.max && keys.length > parseInt(this.max)) {pruneCacheEntry(cache, keys[0], keys, this._vnode)}}// 将组件的keepAlive属性设置为truevnode.data.keepAlive = true // 作用:判断是否要执行组件的created、mounted生命周期函数}return vnode || (slot && slot[0])
}

keep-alive 具体是通过 cache 数组缓存所有组件的 vnode 实例。当 cache 内原有组件被使用时会将该组件 key 从 keys 数组中删除,然后 push 到 keys数组最后,以便清除最不常用组件。

实现步骤:

  1. 获取 keep-alive 下第一个子组件的实例对象,通过他去获取这个组件的组件名
  2. 通过当前组件名去匹配原来 include 和 exclude,判断当前组件是否需要缓存,不需要缓存,直接返回当前组件的实例vNode
  3. 需要缓存,判断他当前是否在缓存数组里面:
    • 存在,则将他原来位置上的 key 给移除,同时将这个组件的 key 放到数组最后面(LRU)
    • 不存在,将组件 key 放入数组,然后判断当前 key数组是否超过 max 所设置的范围,超过,那么削减未使用时间最长的一个组件的 key
  4. 最后将这个组件的 keepAlive 设置为 true

keep-alive 本身的创建过程和 patch 过程

缓存渲染的时候,会根据 vnode.componentInstance(首次渲染 vnode.componentInstance 为 undefined) 和 keepAlive 属性判断不会执行组件的 created、mounted 等钩子函数,而是对缓存的组件执行 patch 过程∶ 直接把缓存的 DOM 对象直接插入到目标元素中,完成了数据更新的情况下的渲染过程。

首次渲染
  • 组件的首次渲染∶判断组件的 abstract 属性,才往父组件里面挂载 DOM
 // core/instance/lifecycle
function initLifecycle (vm: Component) {const options = vm.$options// locate first non-abstract parentlet parent = options.parentif (parent && !options.abstract) { // 判断组件的abstract属性,才往父组件里面挂载DOMwhile (parent.$options.abstract && parent.$parent) {parent = parent.$parent}parent.$children.push(vm)}vm.$parent = parentvm.$root = parent ? parent.$root : vmvm.$children = []vm.$refs = {}vm._watcher = nullvm._inactive = nullvm._directInactive = falsevm._isMounted = falsevm._isDestroyed = falsevm._isBeingDestroyed = false
}
  • 判断当前 keepAlive 和 componentInstance 是否存在来判断是否要执行组件 prepatch 还是执行创建 componentlnstance
// core/vdom/create-component
init (vnode: VNodeWithData, hydrating: boolean): ?boolean {if (vnode.componentInstance &&!vnode.componentInstance._isDestroyed &&vnode.data.keepAlive) { // componentInstance在初次是undefined!!!// kept-alive components, treat as a patchconst mountedNode: any = vnode // work around flowcomponentVNodeHooks.prepatch(mountedNode, mountedNode) // prepatch函数执行的是组件更新的过程} else {const child = vnode.componentInstance = createComponentInstanceForVnode(vnode,activeInstance)child.$mount(hydrating ? vnode.elm : undefined, hydrating)}},

prepatch 操作就不会在执行组件的 mounted 和 created 生命周期函数,而是直接将 DOM 插入

LRU (least recently used)缓存策略

LRU 缓存策略∶ 从内存中找出最久未使用的数据并置换新的数据。
LRU(Least rencently used)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是 "如果数据最近被访问过,那么将来被访问的几率也更高"。 最常见的实现是使用一个链表保存缓存数据,详细算法实现如下∶

  • 新数据插入到链表头部
  • 每当缓存命中(即缓存数据被访问),则将数据移到链表头部
  • 链表满的时候,将链表尾部的数据丢弃。

keep-alive 理解 如何实现?缓存是什么?相关推荐

  1. (转载)彻底理解浏览器的缓存机制

    彻底理解浏览器的缓存机制 2018/04/16 概述 浏览器的缓存机制也就是我们说的HTTP缓存机制,其机制是根据HTTP报文的缓存标识进行的,所以在分析浏览器缓存机制之前,我们先使用图文简单介绍一下 ...

  2. serversocket 返回浏览器图片_深入理解浏览器的缓存机制

       戳蓝字「前端技术优选」关注我们哦! 一.前言 缓存可以说是性能优化中简单高效的一种优化方式了.一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽 ...

  3. 如何理解Spring对缓存的支持

    1.Spring缓存机制的理解 在Spring缓存机制中,包括了两个方面的缓存操作:1.缓存某个方法返回的结果:2.在某个方法执行前或后清空缓存. 下面写两个类来模拟Spring的缓存机制: pack ...

  4. 深入理解:顶点缓存对象(VBO)

    深入理解:顶点缓存对象(VBO) 顶点缓存对象(VBO) 深入理解:顶点缓存对象(VBO) 前言 一.创建VBO 二.绘制VBO 更新VBO 实例 源码下载 引用 前言 GL_ARB_vertex_b ...

  5. 深入理解MyBatis一级缓存和二级缓存【超详细源码解析】

    视频地址:https://www.bilibili.com/video/BV1nP411A7Gu MyBatis的缓存是一个常见的面试题 一级缓存的作用域为何是 sqlSession.二级缓存的作用域 ...

  6. max点缓存烘焙帧_深入理解浏览器的缓存机制

    一.前言 缓存可以说是性能优化中简单高效的一种优化方式了.一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷. 对于一个数据请求来说,可 ...

  7. 深入理解分布式技术 - 缓存高可用

    文章目录 Pre Redis 的主从复制 Redis Sentinel--Redis 哨兵 Redis Cluster 集群 Twemproxy (Twitter) Codis(豌豆荚) Redis ...

  8. html5 客户端数据缓存机制,深入理解HTML5离线缓存机制

    TML5提供了一种离线应用缓存机制,使得网页应用可以离线使用,这种机制在移动端浏览器上支持度非常广,所有版本的android和ios浏览器都能很好的支持.我们可以放心的使用该特性来加速移动端页面的访问 ...

  9. android分享图片功能实现原理,Android:简单实现并理解图片三级缓存

    学习Android网络开发的过程中,势必会经历很多痛苦的过程,其中一个大坑就是图片缓存,当然现在有很多现成的库非常方便,常常几行代码就可以实现想要的功能,但不懂其中的原理是不行的,所以对于刚开始学习网 ...

  10. 深入理解volatile关键字---缓存一致性原理

    volatile关键字与缓存一致性 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java ...

最新文章

  1. oracle命令导入表
  2. 配置C++和C#开发ICE环境
  3. 电子商务之表示层分析(九)
  4. python按概率输出分类结果_sklearn例程:多分类输出概率
  5. pycharms怎么看文件被什么引用_办公室文件柜怎么选,选购文件柜有什么窍门
  6. python智能识别_Python人工智能识别文字内容(OCR)
  7. 体育场[带权并查集]
  8. [NOI2012(bzoj2879)(vijos1726)]美食节 (费用流)
  9. [CSS] Use CSS Counters to Create Pure CSS Dynamic Lists
  10. mysql数据库优化看的书_MySQL 数据库优化,看这篇就够了
  11. c语言编写电子秒表程序,电子秒表C程序.doc
  12. BZOJ1787 Meet紧急集合
  13. [工具] Numpy
  14. 区块链 Fisco bcos 智能合约(12)-Solidity的基础特性
  15. 数据对比,四个角度看中国公募基金的未来
  16. kindle 3 webbrowser破解,
  17. vscode编程字体设置与修改
  18. 园区网络IP地址规划
  19. IT服务管理流程控制主要绩效指标有哪些?
  20. ​有哪些比较好的录制游戏视频软件​,游戏录屏软件哪个好用

热门文章

  1. Parallels Desktop v17.1.1 网络初始化失败
  2. endl和\n的区别
  3. JAVA根据word模版使用poi导出word文档,包含图片、文字
  4. 伊拉克COR证书电子电器
  5. 值得感谢的10位顶级游戏制作人
  6. Android动画(翻牌抽奖)
  7. 【搞定算法】蓄水池算法
  8. ChatGPT教程之 01 什么是ChatGPT革命性的对话生成新工具
  9. 实现淘宝、京东、哔哩哔哩等网站公祭日界面变灰操作
  10. html5柱状图模板,html5生成柱状图(条形图)