Vue3 keep-alive核心源码的解析

在 Vue 3 中,<keep-alive> 组件的源码实现比较复杂,但主要涉及的是组件实例的缓存、生命周期钩子的管理、以及缓存策略。以下是对其核心源码的解析。

1. KeepAlive 的核心结构

<keep-alive> 组件的核心在于它如何管理组件实例的缓存,以及如何在组件被复用和销毁之间做切换。以下是 KeepAlive 的基本实现结构。

javascript 复制代码
export const KeepAlive = {
  name: 'KeepAlive',
  __isKeepAlive: true, // 标识为 KeepAlive 组件

  props: {
    include: [String, RegExp, Array],
    exclude: [String, RegExp, Array],
    max: [String, Number]
  },

  setup(props, { slots }) {
    // 缓存和最近使用缓存的 key 队列
    const cache = new Map();
    const keys = new Set();

    // 当前激活的组件实例
    let current = null;

    // 返回虚拟节点的 render 函数
    return () => {
      const vnode = slots.default();
      if (!vnode) return null;

      const name = vnode.type.name || vnode.key;
      if (name && shouldCache(name, props.include, props.exclude)) {
        if (cache.has(vnode.key)) {
          vnode.component = cache.get(vnode.key).component;
          // 更新 key 的使用顺序
          keys.delete(vnode.key);
          keys.add(vnode.key);
        } else {
          cache.set(vnode.key, vnode);
          keys.add(vnode.key);

          // 如果超过缓存数量限制,则移除最早使用的缓存
          if (props.max && keys.size > parseInt(props.max, 10)) {
            const firstKey = keys.values().next().value;
            cache.delete(firstKey);
            keys.delete(firstKey);
          }
        }

        vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE;
      }

      current = vnode;
      return vnode;
    };
  }
};

2. KeepAlive 的核心逻辑

KeepAlive 的源码中,以下几个核心部分需要关注:

a. 缓存机制(cachekeys
  • cache 是一个 Map 对象,用于存储被缓存的组件实例。
  • keys 是一个 Set 对象,记录了缓存组件的 key 顺序,便于管理缓存的顺序。
  • vnode.key 被用作缓存的 key,确保每个实例的唯一性。
b. shouldCache 函数

shouldCache 用于判断当前组件是否符合缓存的条件。它会检查 includeexclude 属性,决定是否要缓存该组件。

javascript 复制代码
function shouldCache(name, include, exclude) {
  if (include && !matches(include, name)) {
    return false;
  }
  if (exclude && matches(exclude, name)) {
    return false;
  }
  return true;
}

function matches(pattern, name) {
  if (Array.isArray(pattern)) {
    return pattern.includes(name);
  } else if (typeof pattern === 'string') {
    return pattern.split(',').includes(name);
  } else if (pattern instanceof RegExp) {
    return pattern.test(name);
  }
  return false;
}
  • include:要缓存的组件列表。
  • exclude:不缓存的组件列表。
c. 缓存的更新和删除

当缓存的数量超过 max 限制时,会移除最早使用的缓存。这是通过 LRU(最近最少使用)策略实现的:

javascript 复制代码
if (props.max && keys.size > parseInt(props.max, 10)) {
  const firstKey = keys.values().next().value;
  cache.delete(firstKey);
  keys.delete(firstKey);
}
  • 每次访问组件时,都会更新 keys 的使用顺序,以保证 keys 最前面的始终是最早使用的组件。
  • 如果 keys.size 超过 max,则会删除最早的 key 和对应的缓存。

3. 生命周期钩子的管理

在 Vue 3 中,KeepAlive 会触发组件的 activateddeactivated 生命周期钩子。以下是相关的核心代码:

  • activated:当缓存组件重新显示时调用。
  • deactivated:当组件被移除但未销毁时调用。
javascript 复制代码
// KeepAlive 组件的生命周期处理
function onActivated(instance) {
  if (instance.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
    queuePostRenderEffect(() => {
      instance.isDeactivated = false;
      if (instance.a) {
        invokeArrayFns(instance.a);
      }
    }, instance.parent);
  }
}

function onDeactivated(instance) {
  if (instance.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
    queuePostRenderEffect(() => {
      instance.isDeactivated = true;
      if (instance.da) {
        invokeArrayFns(instance.da);
      }
    }, instance.parent);
  }
}
  • onActivated :在 KeepAlive 缓存的组件被重新渲染时,会调用该函数,使组件的 isDeactivated 状态为 false,并执行 activated 钩子。
  • onDeactivated :当组件被移除但未销毁时调用 onDeactivated,将 isDeactivated 状态设置为 true,并调用 deactivated 钩子。

4. 总结

<keep-alive> 的核心逻辑包括:

  • 缓存策略 :通过 cachekeys 实现 LRU 策略管理。
  • 条件判断 :通过 includeexclude 判断是否缓存组件。
  • 生命周期钩子 :控制缓存组件的 activateddeactivated 状态。

KeepAlive 组件的实现充分考虑了缓存的性能和灵活性,允许开发者通过配置来控制组件缓存的行为,有效地提升了应用的性能。

相关推荐
高山我梦口香糖26 分钟前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_7482352429 分钟前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240251 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar1 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人2 小时前
前端知识补充—CSS
前端·css
GISer_Jing2 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_748245522 小时前
吉利前端、AI面试
前端·面试·职场和发展
理想不理想v2 小时前
webpack最基础的配置
前端·webpack·node.js
pubuzhixing3 小时前
开源白板新方案:Plait 同时支持 Angular 和 React 啦!
前端·开源·github
2401_857600953 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js