首页 > 其他分享 >#yyds干货盘点#前端keepalive缓存清理

#yyds干货盘点#前端keepalive缓存清理

时间:2022-12-05 22:32:00浏览次数:51  
标签:yyds 缓存 cache vnode Vue key exclude keepalive 页面

说到 ​​Vue​​​ 缓存,我们肯定首先选择官方提供的缓存方案 ​​keep-alive​​ 内置组件来实现。

​keep-alive​​ 组件提供给我们缓存组件的能力,可以完整的保存当前组件的状态,这帮了我们很大的忙

但实际业务场景中,我们很多时候是按需缓存页面的,就像 ​​App​​​ 开发那样,每个页面都是单独的一个页面实例,由于 ​​Vue Router​​​ 的限制,每个页面有固定的一个 ​​path​​​,所以导致每次访问这个 ​​path​​ 都会命中同一个组件实例。

有人会说,用生命周期activated来实现。没错,是可以这样,但是,有些操作是 ​​mounted​​ 里面要做,有些需要放到 ​​activated​​ 里面更新,代码要处理很多进入页面的操作,就很麻烦啊。

此时就有两个思考方向:

  1. 在必要的时候清除掉缓存页面的实例。
  2. 每次 push 页面的时候,保证当前页面是全新的实例对象,和 ​​App​​ 页面栈相同。

第二种方案可以比较物理的解决需求中的问题,但是需要改动的地方很多,比如 ​​Vue Router​​ 中路由切换的时候,是否采用动态生成 ​​path​​ ,确保当前页面实例不唯一,而且我们也要做好自己的页面栈管理,类似于 ​​iOS​​ 中的 ​​UINavigationController​​ ,以便于及时清理栈中缓存的页面实例

因为改动比较大,而且需要大量测试,所以最后还是选择在方案一的方向进行探索和尝试。

 手动操作 ​​keep-alive​​​ 组件的 ​​cache​​ 数组

//  Vue 2 keep-alive 部分源码片段
const { cache, keys } = this;
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;
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance;
// make current key freshest
remove(keys, key);
keys.push(key);
} else {
// delay setting the cache until update
this.vnodeToCache = vnode;
this.keyToCache = key;
}

通过路由守卫在特定的情况下删除 ​​cache​​​ 数组中的页面实例,同时 ​​destory​​ 当前实例

removeKeepAliveCacheForVueInstance(vueInstance) {
let key =
vueInstance.$vnode.key ??
vueInstance.$vnode.componentOptions.Ctor.cid + (vueInstance.$vnode.componentOptions.tag ? `::${vueInstance.$vnode.componentOptions.tag}` : "");
let cache = vueInstance.$vnode.parent.componentInstance.cache;
let keys = vueInstance.$vnode.parent.componentInstance.keys;
if (cache[key]) {
vueInstance.$destroy();
delete cache[key];
let index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
}
}

这种方案比较繁琐,但由于是直接操作 ​​cache​​ 数组,可能会产生一些预期外的泄漏问题或者运行问题,虽然我自己尝试的时候没有发现。。

在 ​​Vue 3​​​ 中我也尝试去寻找对应的 ​​cache​​​ 数组,还真被我找到了,但是 ​​Vue 3​​​ 源码中对于 ​​cache​​ 数组的操作权限仅限于开发环境。

// Vue 3 KeepAlive 组件片段
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
;(instance as any).__v_cache = cache
}

部署生产环境之后就没办法通过 ​​instance.__v_cache​​​ 来获取 ​​cache​​ 数组了,所以这种方案到 Vue 3 就没办法进行下去啦。

于是乎,就有了第二个尝试。


​exclude​​ 大法好

之前接触 ​​keep-alive​​ 所有注意力都放在 ​​include​​ 这个属性上面,其实 ​​exclude​​ 属性同样重要,而且效果和我们直接删除 ​​cache​​ 数组异曲同工。

// Vue 3 KeepAlive 组件片段
if (
(include && (!name || !matches(include, name))) ||
(exclude && name && matches(exclude, name))
) {
current = vnode
return rawVNode
}

如果 ​​exclude​​​ 里面有值,那么就返回当前新的实例不从 ​​cache​​​ 里面获取。而且 ​​exclude​​​ 的优先级是高于 ​​include​​ 的。

利用这一点,我们就可以通过操作 ​​exclude​​ 中的内容,来达到控制缓存页面的效果。

而且 ​​exclude​​ 在 ​​Vue 3​​ 中的控制更为方便,只需要定义一个全局的 ​​exclude​​ 响应式变量就可以随处操作了,清除的具体方式取决于业务流程

export const excludes = ref<string[]>([]);
// 需要删除的时候
export function removeKeepAliveCache(name: string) {
excludes.value.push(name);
}
// 需要恢复缓存的时候
export function resetKeepAliveCache(name: string) {
excludes.value = excludes.value.filter((item) => item !== name);
}

标签:yyds,缓存,cache,vnode,Vue,key,exclude,keepalive,页面
From: https://blog.51cto.com/u_11365839/5913316

相关文章