[qiankun]-多页签缓存

news/2024/3/29 23:20:52/文章来源:https://blog.csdn.net/tjj3027/article/details/129161448

[qiankun]-多页签缓存

  • 环境
  • 功能需求
  • 多页签缓存方案
    • 方案1.主服务进行html替换
    • 方案2.微服务vnode 替换
    • 方案3.每个微服务都不卸载
      • 微服务加载方式的选择
      • 微服务的路由路径选择
      • 微服务的缓存工具
      • 微服务的容器
        • 使用tab作为微服务的挂载容器
        • 使用微服务路由作为微服务的挂载容器
          • 场景描述
      • 微服务的缓存
        • 缓存微服务
        • 删除微服务
        • 不同路由同一微服务情况

管理系统比较常用的一个功能就时多页签的缓存,我们通过缓存已经打开的页签,并在切换页签的时候看到之前的查询结果,在关闭页签的重新点击菜单那时,看到的是新的没有查询记录界面

环境

语言:采用的主流的vue3.x+ts开发
UI框架:使用的是ant-design框架
其它工具:使用了微服务技术-qiankun
缓存工具:keep-alive

功能需求

  • 通过点击菜单,打开一个菜单页签(点击后展示的菜单称之为页签):

    如果点击菜单之前已打开页签中没有该菜单,则该页面应该是初始页面状态;

    如果点击菜单之前已打开页签中有该菜单,则该页面应该是上次操作后状态;

  • 切换已打开的页签:

    则页面应该都是上次操作后状态;

  • 关闭页签后再次点击菜单:

    因为点击菜单之前关闭页签,所以已打开页签中没有该菜单,则该页面应该是初始页面状态;

多页签缓存方案

方案1.主服务进行html替换

通过存储每个微服务容器的html内容,然后在切回当前页签的时候,微服务容器使用缓存的html替换,也就是所谓的替换innerHTML。

方案尝试结果描述:
替换的内容,使得切换回原有页面确实是上次的查询结果页面,但是页面失去了响应性,变成了静态的HTML页面,包括下拉框都没有了

方案2.微服务vnode 替换

通过存储每个微服务容器的 vnode 内容,然后在切回当前页签的时候,创建微服务实例的时候,使用vnode替换掉原有的render渲染函数

方案尝试结果描述:
因为本人使用的vue3开发,使用render渲染函数是vue2创建vue实例的方法,因此该方案无法实现使用vnode替换掉原有的render渲染函数

尝试了vnode的缓存强制替换的可能性,vue3提示_vnode是只读属性不可以设置

方案3.每个微服务都不卸载

以上两个方案,都是基于同时只加载一个微服务,并且在切换的时候卸载当前微服务,之所以先尝试前两个方案也是因为,如果页面每个微服务都不卸载,当打开的页签过多时会有性能问题,因为微服务总数量暂时有限,该问题此时先不考虑了,如果之后有需要会另外总结

因为前两个方案都不可行,只能尝试该方案,方案描述:

微服务加载方式的选择

qiankun加载加载微服务的方式有两种:

  1. 是注册加载,通过劫持路由,会根据路由变化加载每个微服务
    registerMicroApps,是根据路由的变化加载微服务的,只要路由变化,就会触发微服务重新加载微服务,因此无法阻止微服务的重新加载,缓存不能被使用,指定容器的内容会被覆盖,因此感觉不适合缓存页签的方案
  2. 是手动加载,可以自己决定什么时候加载
    loadMicroApp ,是手动加载,因此能决定是重新加载,还是使用缓存,感觉适合使用该方式

因此选择手动加载微服务的方式

微服务的路由路径选择

主服务具有公共页面,例如404,intro等路由页面,公共页面与微服务都是展示在页面的主体区,并且不需要缓存,因为没有操作功能,当然缓存也是可以的。微服务展示的时候,公共路由页面不可展示,路由也需要变为微服务的路由,不能使用之前的路由路径。

因此可以使用router.push(),或者router.replace()改变浏览器的路由路径,有说可以把路由router想象成一个访问记录的栈,router.replace() 是替换掉栈顶,而router.push() 则是向栈中再堆入一个新记录

考虑过所有微服务使用同一个路由路径,但是因为浏览器的前进后退记录管理服务,因此每个微服务的路由路径不能完全相同,否则无法区分微服务的前进后退记录,所以也不能使用replace方法了

因此每个微服务页面具有一个唯一的路由路径,需要使用router.push记录所有的路由路径,并且需要用来加载微服务的路由组件(如果没有找到指定的路由,系统会跳转404,因此需要微服务的路由组件,微服务众多,因此所有微服务可以采用相同的前缀,用以匹配到同一个路由组件),一个微服务路由组件就能够满足需求

相同的前缀,/micro/XXXX/XXXX,例如:/micro/service/function

{path: "/micro/:pathMatch(.*)*",///micro/:projectName/:pagemeta: { auth: true },component: () => import(/* webpackChunkName: "micro" */ "../micro/index.vue")}

微服务的缓存工具

默认情况下,一个组件实例在被替换掉后会被销毁。这会导致它丢失其中所有已变化的状态 —— 当这个组件再一次被显示时,会创建一个只带有初始状态的新实例。

keep-alive 是 vue 内置的动态组件缓存工具

keep-alive 缓存路由的key默认是每个路由的name,一般的路由缓存因为每个路由设置了不同的name,所以include包含需要缓存的路由的name即可

那么针对想更改缓存Key的情况:

<router-view v-slot="{ Component, route }"><keep-alive :include="cachePannels"><component :is="wrap(route, Component)" :key="wrapKey(route.path)" /></keep-alive>
</router-view>

以下对component与key的处理,PROJECT.cacheKey设置缓存的key字段:

const wrap = (route, component) => {component.type.name = "path" == PROJECT.cacheKey ? route.path : store.state.pathMap[route.path].id;return component
};
const wrapKey = (path) => {if ("path" == PROJECT.cacheKey) {return path} else {return store.state.pathMap[path].id}
}

经过测试发现若缓存的字段是path,则缓存成功,若是key是改成id则缓存不成功,因为对于源码的理解并不深入,所以目前并不理解原因,也暂时不做深入,这里还是想吐槽一句,看到在源码处这个问题已经被提出几年了,但是都没有一个官方正式的回应,都是小伙伴提供的各种解决方案,而且就像上面说的绑定的key还必须是path其它不可以。。。

好吧,暂时不纠结了,既然path可用,就确定使用path,以下是最终代码

<router-view v-slot="{ Component, route }"><keep-alive :include="cachePannels"><component :is="wrap(route, Component)" :key="route.path" /></keep-alive>
</router-view>
const wrap = (route, component) => {component.type.name = route.path;return component
};

因为微服务使用的是同一个路由组件,因此name相同,那么正好需要使用根据key进行缓存的功能

基于上述原因,使用keep-alive缓存,路由path,作为缓存的key。

关于keep-alive重写的功能以后有机会在尝试吧

微服务的容器

一开始我是倾向于直接用微服务路由组件作为加载微服务的容器

但是使用路由的path作为路由缓存的key,理论讲一旦path发生变更,则路由组件会被销毁重新加载,但是微服务切换时到底组件是否会被销毁?在尝试时存在一些无可避免的问题,当时没有成功

使用tab作为微服务的挂载容器

这里先讲述一个成功缓存的方式

<template>
<a-tabs  v-model:activeKey="activeKey"@tabClick="clickTab"  @edit="closeTab"><a-tab-pane v-for="item in cacheList" :key="item.id" :tab="item.title"><div :id="'micro'+item.id" class="micro-tab"></div></a-tab-pane>
</a-tab><router-view v-slot="{ Component, route }"><keep-alive :include="cachePannels"><component :is="wrap(route, Component)" :key="route.path" /></keep-alive>
</router-view>
</template>

微服务路由 micro.vue

<template>
</template>
<script lang="ts" setup>
import { useStore } from "store";
const store = useStore();
store.commit("loadMicroApp");
</script>

注意,虽然微服务加载是在tab中挂载的,但是router-view此时是要正常加载微服务路由的,因为路径要有对应的匹配路由,但是微服务又不在其中挂载,所以隐藏微服务路由 micro.vue 的展示即可

使用微服务路由作为微服务的挂载容器

加载的时候,因为使用的path作为key,理论来讲,keep-alive应该将每个微服务作为一个单独的路由进行缓存.

但是实际情况有所不同,现象描述:

在打开页签的过程中,每次都是onMount了的,切换的时候,可以看到确实缓存了微服务,每次切换的时候显示的是缓存页面

但是在关闭页签的时候出现了问题,一旦关闭了其中一个正在展示的微服务,其它微服务页面就白屏了,就像是其它路由组件都被删除了?!所以为什么作为单独路由缓存的其它页面没有正常展示?但是如果关闭的是没有展示的页签,则并不影响当前路由的展示与后续的切换

因为该问题没有解决,所以最终没有采用该方式!!下面采用路由组件作为容器时的现象

场景描述

主服务首次点击菜单A,打开页签A,挂载A服务 onMounted onActivated

主服务首次点击菜单B,打开页签B,挂载B服务 onMounted onActivated

切换A服务,B onDeactivated,A onActivated

切换B服务,A onDeactivated,B onActivated

此时关闭B服务:

实际:B onUnmounted,A onMounted onActivated

理论:B onUnmounted,A onActivated

这就像是A挂载到了B的路由组件上了?
正常的切换时keep-alive缓存的组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61K3ycOm-1677045679175)(2023-01-03-11-37-19.png)]

vue 的组件,不同路径,同一个路由, 缓存的组件为同一个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7wZSirDR-1677045679177)(2023-01-03-15-16-52.png)]

在这里插入图片描述

因此同组件路由卸载的时候,另外的就无法展示了,原因找到了,但是如何区分开?尝试过使用cloneVnode 克隆micro.vue组件,但是无效,所以暂时未找到解决方案

微服务的缓存

缓存微服务

需要缓存的微服务正常手动加载微服务即可,并缓存该微服务

最早的时候是直接缓存的

cacheMap[microApp.path] = loadMicroApp(microApp)

后来在实践中发现直接缓存是存在问题的,例如当loadMicroApp失败的时候(微服务不存在,不可用的情况),此时缓存的微服务实例是不存在的,自然对于该微服务实例后续的卸载会导致报错

因此,当缓存微服务的时候需要确保微服务加载成功:

const appMicro = loadMicroApp(microApp, { singular: false }, microLifeCycle);
appMicro.mountPromise.then((res) => {//微服务加载成功时保存微服务state.micro.cacheMap[microApp.path] = appMicro;
}).catch((error) => {//微服务加载失败时提示错误console.error(`mountPromise error`, error)
})

microLifeCycle是微服务的生命周期,可以在其中设置微服务的加载动画

删除微服务

关闭页签,也就是删除缓存微服务时,注意一定要先卸载微服务,unmount,否则下次加载该微服务时会报已挂载错误

//卸载微服务
cacheMap[microApp.path].unmount();
//删除微服务实例
delete cacheMap[microApp.path]

不同路由同一微服务情况

如果微服务有两个路由,而两个路由页面都点击后要缓存,此时也是正常加载即可,当作两个不同微服务加载即可,也不会报已挂载错误,因为路径不同可以当作缓存的是两个微服务(不同于在micro.vue中挂载,该路由组件中如果当作两个微服务挂载是会报已挂载错误的),因为是加载在tab中,彼此并不互相影响

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_72727.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

干货解答:如何设置Facebook Messenger 自动回复?

Facebook Messenger 自动回复消息是提升客户体验的有效方法。在本文中&#xff0c;我们将探讨设置Facebook 自动响应和不同的创建方法 Facebook 自动回复。另外&#xff0c;我们准备了一些最受欢迎的 Facebook Messenger 自动回复消息。Facebook Messenger 自动回复&#xff1a…

https加密原理详解,带你搞懂它为什么比http更安全

文章目录http的缺点对称加密非对称加密数字签名数字证书验证身份数字摘要数字签名验证内容的完整性总结http的缺点 http是超文本传输协议&#xff0c;使用http协议进行通信有如下缺点&#xff1a; http没有提供任何数据加密机制&#xff0c;数据通信使用明文通信&#xff0c;…

x86架构设备的OpenWrt的空间扩容问题

openwrt固件是squashfs-combined-efi非exf4格式 直接将原有根分区扩容 用插件是&#xff1a;fdisk,losetup,resize2fs,blkid df -h fdisk -l fdisk /dev/sda //进入fdisk分区管理工具注意fdisk后参数是磁盘名称&#xff0c;是要根据实际情况填写 fdisk /dev/sda //进入fdi…

JavaEE简单示例——<select>中的查询参数传递和结果集封装自动映射关系

简单介绍&#xff1a; 在之前我们在讲SQL映射文件中的映射查询语句的<select>标签的时候&#xff0c;对其中的四个常用属性的讲解并不是那么的透彻&#xff0c;今天就来详细的解释<select>的四个常用属性的具体含义以及<select>标签在进行查询的时候查询参数…

Sofa-jraft的Rpc调用服务端分析

在sofa-jraft中&#xff0c;关于RPC的服务端是RpcServer在RpcServer中的init方法中&#xff1a;初始化了连接事件监听器&#xff0c;这个里面就是一个map&#xff0c;然后可以添加事件监听的处理器&#xff0c;初始化userProcessors, codec 是一个编码和解码器的工厂&#xff0…

2022-2023年营销报告(B站平台) | 5大行业势态、流量大盘全景洞察

一直以来&#xff0c;手持高活跃、高粘性用户群体的B站是行业用来观察年轻人消费习惯的重要平台。以至于用户群体的不断壮大带动了B站的商业价值。如今B站的商业舞台越来越大&#xff0c;不断地向外界招手&#xff0c;欢迎更多品牌积极加入到这个千万年轻人聚集的内容社区。为了…

基于Hibernate对数据库表的单表查询

基于Hibernate对数据库表的单表查询 1.依赖 1.1jar包 1.2配置文件。persistence.xml <?xml version"1.0" encoding"UTF-8"?> <persistence version"2.1"xmlns"http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi"…

亲身试验 Outlook防关联方法分享

Outlook在海外的用途是很广泛的&#xff0c;不仅可以用于收发邮件&#xff0c;还可以作为各类第三方网站的登录凭证。所以Microsoft对于Outlook的监管还是比较严格的&#xff0c;跨境卖家大量注册Outlook账号使用的话很容易被检测出关联然后被封号。龙哥针对Outlook防关联的问题…

【Kubernetes 入门实战课】Day02——初识容器

系列文章目录 【Kubernetes 入门实战课】Day01——搭建kubernetes实验环境(一) 文章目录系列文章目录前言一、Docker的诞生二、Docker的形态1、Docker Desktop2、Docker Engine二、Docker的安装1、服务器连接外网安装2、服务器不通外网三、Docker的使用三、Docker的架构总结前…

阿里云物联网平台设备模拟器

在使用阿里云物联网平台过程中&#xff0c;如果开始调试没有实际的物理设备&#xff0c;可以考虑在阿里云物联网平台使用官方自带的模拟器进行调试。不过也可以通过叶帆科技开发的阿里云物联网平台设备模拟器AliIoTSimulator进行调试&#xff0c;AliIoTSimulator可以独立运行&a…

stm32 VM8978 音乐播放

一、WAV文件 1、WAV文件简介 2、WAV文件的解析 二、WM8978 1、WM8978介绍 2、WM8978特点 3、WM8978接口 4、WM8978框架 5、 WM8978 寄存器 三、IIS详解 1、IIS介绍 2、 IIS 的特点 3、IIS框架 4、 音频协议 5、 IIS Philips 标准 6、 IIS 时钟 四、音乐播放硬件…

ChatGPT三个关键技术

情景学习&#xff08;In-context learning&#xff09; 对于一些LLM没有见过的新任务&#xff0c;只需要设计一些任务的语言描述&#xff0c;并给出几个任务实例&#xff0c;作为模型的输入&#xff0c;即可让模型从给定的情景中学习新任务并给出满意的回答结果。这种训练方式能…

双检测人脸防伪识别方法(活体检测+人脸识别+关键点检测+人像分割)

双检测人脸防伪识别=人脸检测+活体检测+人脸识别 1.人脸关键点+语义分割 使用mediapipe进行视频人脸关键点检测和人像分割: import time import cv2 import mediapipe as mp import numpy as npmp_drawing = mp.solutions.drawing_utils mp_drawing_styles = mp.solution…

量化交易-单因子分析-alphalens

1. 数据准备 1.1 计算因子IC重要函数 def get_clean_factor_and_forward_returns(factor,prices,groupbyNone,binning_by_groupFalse,quantiles5,binsNone,periods(1, 5, 10),filter_zscore20,groupby_labelsNone,max_loss0.35,zero_awareFalse,cumulative_returnsTrue)facto…

【C语言】-程序编译的环境和预处理详解-让你轻松理解程序是怎么运行的!!

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 程序的编译前言一、 程序的翻译环境和执行环境二、 详解翻译环境2.1编译环境2.1.1预编…

民锋国际期货:2023,既艰难又充满希望,既纷乱又有无数机会。

不管是官方还是民间&#xff0c;各种信号都表明&#xff0c;2023年是一个拼经济的年份。 通货膨胀带来的需求量的增加&#xff0c;与中国经济高速发展带来的供给量增加&#xff0c;二者共同构成了我们的物价。 做一个长期主义者&#xff0c;做一个坚定看好中国未来的人&#…

MapBox动态气泡图渲染教程

先来看效果: 视频效果: 屏幕录制2023-02-22 15.34.57 首先我们来介绍一下思路。对于mapbox和openlayers这样的框架来讲,气泡图中的气泡本质上就是一个div,就是将一个dom元素追加到canvas上的固定位置而已。 在mapbox中有marker的概念,官网也有示例: Attach a popup to …

二叉树——路径总和

路径总和 链接 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点…

数据库及缓存之MySQL(一)

思维导图 常见知识点 1.mysql存储引擎&#xff1a; 2.innodb与myisam区别&#xff1a; 3.表设计字段选择&#xff1a; 4.mysql的varchar(M)最多存储数据&#xff1a; 5.事务基本特性&#xff1a; 6.事务并发引发问题&#xff1a; 7.mysql索引&#xff1a; 8.三星索引&#xf…

升职加薪必备,2023年程序员不能不知道的AI辅助编码工具

已经有很多人把chatGPT当做必备的Bug修复工具了&#xff0c;对于用AI写代码&#xff0c;有人感到失落&#xff0c;害怕被取代&#xff0c;而另一些人则认为人工智能将加快编写更好代码的过程。 尽管 AI 编写的代码并非完美无缺&#xff0c;但我相信&#xff0c;最终AI将取代人…