当前位置: 首页 > news >正文

在vue中对keep-alive的理解,它是如何实现的,具体缓存的是什么?

对keep-alive的理解,它是如何实现的,具体缓存的是什么?

  • (1)keep-alive有以下三个属性:
    • 注意:keep-alive 包裹动态组件时,会缓存不活动的组件实例。
    • 主要流程
  • (2)keep-alive 的实现
    • render函数
  • (3)keep-alive 本身的创建过程和 patch 过程
  • (4)LRU (least recently used)缓存策略

如果需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。

(1)keep-alive有以下三个属性:

include 字符串或正则表达式,只有名称匹配的组件会被匹配;
exclude 字符串或正则表达式,任何名称匹配的组件都不会被缓存;
max 数字,最多可以缓存多少组件实例。

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

主要流程

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

(2)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,判断当前组件是否需要缓存,不3.需要缓存,直接返回当前组件的实例vNode需要缓存,判断他当前是否在缓存数组里面:
(1)存在,则将他原来位置上的 key 给移除,同时将这个组件的 key 放到数组最后面(LRU)
(2)不存在,将组件 key 放入数组,然后判断当前 key数组是否超过 max 所设置的范围,超过,那么削减未使用时间最长的一个组件的 key
4.最后将这个组件的 keepAlive 设置为 true

(3)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 插入

(4)LRU (least recently used)缓存策略

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

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

相关文章:

在vue中对keep-alive的理解,它是如何实现的,具体缓存的是什么?

对keep-alive的理解&#xff0c;它是如何实现的&#xff0c;具体缓存的是什么&#xff1f; &#xff08;1&#xff09;keep-alive有以下三个属性&#xff1a;注意&#xff1a;keep-alive 包裹动态组件时&#xff0c;会缓存不活动的组件实例。主要流程 &#xff08;2&#xff09…...

章节一、认识three.js与开发环境学习笔记01;

一、如何学习WEB可视化3D技术与课程内容演示&#xff1b; 1、项目案例&#xff1a; 政府有大量的新基建的项目&#xff1a;如数字孪生、智慧城市、智慧园区、智慧工厂、智慧消防等等都涉及了3d的可视化技术&#xff1b; 2、如何系统的学号WEB 3D可视化技术&#xff1f; three…...

QT摄像头采集

主界面为显示框&#xff0c;两个下拉框&#xff0c;一个是所有相机&#xff0c;一个是相机支持的分辨率 系统根据UI界面自动生成的部分不再描述&#xff0c;以下为其他部分源码 widget.h #include <QWidget> #include <QMouseEvent> class QCamera; class QCamer…...

C语言第三十四弹---动态内存管理(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 动态内存管理 1、动态内存经典笔试题分析 1.1、题目1 1.2、题目2 1.3、题目3 1.4、题目4 2、柔性数组 2.1、柔性数组的特点 2.2、柔性数组的使用 2.3、…...

PDN分析及应用系列二-简单5V电源分配-Altium Designer仿真分析-AD

PDN分析及应用系列二 —— 案例1:简单5V电源分配 预模拟DC网络识别 当最初为PCB设计打开PDN分析仪时,它将尝试根据公共电源网络命名法从设计中识别所有直流电源网络。 正确的DC网络识别对于获得最准确的模拟结果非常重要。 在示例项目中已经识别出主DC网络以简化该过程。 …...

Vue开发实例(一)Vue环境搭建第一个项目

Vue环境搭建&第一个项目 一、环境搭建二、安装Vue脚手架三、创建Vue项目 一、环境搭建 下载方式从官网下载&#xff1a;http://nodejs.cn/download/ 建议下载v12.16.0版本以上的&#xff0c;因为版本低无法创建Vue的脚手架 检验是否安装成功 配置环境变量 新增NODE_HOME&…...

将SpringBoot项目改造成solon项目

solon项目介绍 官网 Java “生态型”应用开发框架&#xff1a;更快、更小、更简单。 启动快 5 &#xff5e; 10 倍&#xff1b;并发高 2&#xff5e; 3 倍&#xff1b; 内存省 1/3 ~ 1/2&#xff1b;打包缩到 1/2 ~ 1/10&#xff1b;同时支持 java8, java11, java17, java21&a…...

更详细的软件测试理论基础:流程,开发、测试模型,测试分类,测试用例及其设计方法,缺陷

文章目录 一、测试流程二、开发模型1、 瀑布模型2、增量模型3、快速模型4、其他 三、测试模型1、V模型2、W模型 四、测试分类五、测试用例 test case六、测试用例设计方法1、等价类划分法2、边界值分析法3、因果图法4、判定表法5、正交法6、场景法7、流程分析法8、错误推测法方…...

input css padding

这样控件会跑出外套控件在HTML JSP里面是经常出现的。但有些外国adobe的as控件不存在这种情况&#xff0c;这是因为内层控件定义的时候不能超出外层控件的范围。 修改下&#xff1a;去掉原来css padding&#xff0c;然后加上宽度和高度...

如何打印 springboot 框架中 接收请求的日志

在 Spring Boot 框架中&#xff0c;您可以使用日志来记录接收请求和发送响应的详细信息。Spring Boot 默认使用 SLF4J&#xff08;Simple Logging Facade for Java&#xff09;作为日志抽象层&#xff0c;并支持多种日志实现&#xff0c;如 Logback、Log4j2 等。以下是一种常见…...

JVM的内存区域划分

JVM即Java虚拟机&#xff0c;是Java实现跨平台交互能力的核心&#xff0c;Java编译后的.class文件&#xff0c;就是通过虚拟机和操作系统进行交互的&#xff1b; 常见的虚拟机有&#xff1a;JVM、VMwave、Virtual Box&#xff0c;目前最主流使用的JVM是HotSpot VM&#xff1b;…...

YOLOv9有效改进|使用动态蛇形卷积Dynamic Snake Convolution

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 使用ICCV2023中的动态蛇形卷积替换YOLOv9网络中的Conv模块。 二、Dynamic Snake Convolution模块详解 2.1 模块简介 应用场景&#x…...

设计模式学习笔记 - 设计原则 - 1.单一职责原则

前言 前面我们提到过 SOLID 原则&#xff0c;实际上 SOLID 由 5 个设计原则组成&#xff0c;分别是&#xff1a;单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖反转原则。它们分别对应 SLOID 中的 S、O、L、I、D 这 5 个英文字母。 今天来学习下 SOLID 原则中的第…...

飞天使-学以致用-devops知识点4-SpringBoot项目CICD实现(实验失败,了解大概流程)

文章目录 代码准备创建jenkins 任务测试推送使用项目里面的jenkinsfile 进行升级操作 文字版本流程项目构建 代码准备 推送代码到gitlab 代码去叩叮狼教育找 k8s 创建jenkins 任务 创建一个k8s-cicd-demo 流水线任务 将jenkins 里面构建时候的地址还有token&#xff0c; 给到…...

使用HTML5画布(Canvas)模拟图层(Layers)效果

使用HTML5画布&#xff08;Canvas&#xff09;模拟图层&#xff08;Layers&#xff09;效果 在图形处理和计算机图形学中&#xff0c;图层&#xff08;Layers&#xff09;是指将图像分成不同的可独立编辑、组合和控制的部分的技术或概念。每个图层都可以包含不同的图形元素、效…...

违背祖训,微软骚操作强制用户更新至 Win 11 23H2

话说&#xff0c;大伙儿有让 Windows 操作系统一直保持最新版习惯吗&#xff1f; 根据以往惯例&#xff0c;Windows 系统更新是个比较玄学的存在&#xff0c;谁也不能保证随手更新后会不会出现什么奇葩 Bug。 因此对于不少同学来说&#xff0c;Windows 更新到一个稳定版本后&a…...

MISRA C++ 2023指南:您需要了解的一切

MISRA C 2023可以帮助使用现代C语言的组织开发安全关键型软件。使用新的MISRA标准&#xff0c;开发人员可以通过确保和记录其软件应用程序的MISRA合规性&#xff0c;满足IEC 6108或ISO 26262等功能安全标准给出的静态分析要求。 什么是MISRA C2023? 以便使用C17进行安全可靠…...

Vue:【亲测可用】父组件数组包对象,传给子组件对象,子组件修改属性(字段)后,父组件没有更新

场景&#xff1a;vue中父组件数组包对象&#xff0c;传给子组件对象&#xff0c;子组件修改属性&#xff08;字段&#xff09;后&#xff0c;父组件没有更新 代码&#xff1a; # 父组件 <div v-for"(object, name, index) in arr" :key"index"><…...

hbase学习十:客户端实现与Meta表解析

1、客户端实现 hbase社区的客户端一般是java客户端。 HBase也支持Shell交互式客户端。Shell客户端实质是用JRuby(用Java编写的Ruby解释器,方便Ruby脚本跑在JVM虚拟机上)脚本调用官方HBase客户端来实现的。因此,各种客户端的核心实现都在社区Java版本客户端上。 客户端访…...

《OpenScene: 3D Scene Understanding with Open Vocabularies》阅读笔记1

传统的3D场景理解方法依赖于带标签的3D数据集,用于训练一个模型以进行单一任务的监督学习。我们提出了OpenScene,一种替代方法,其中模型在CLIP特征空间中预测与文本和图像像素共同嵌入的3D场景点的密集特征。这种零样本方法实现了与任务无关的训练和开放词汇查询。例如,为了…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...