【vue篇】Vue 性能优化神器:keep-alive 深度解析与实战指南

在 Vue 开发中,你是否遇到过:

"切换页面时,列表滚动位置丢失?"
"组件反复创建销毁,性能卡顿?"
"表单输入内容在路由切换后清空?"

keep-alive 就是解决这些问题的"银弹"。

它能缓存组件状态,避免重复渲染,大幅提升用户体验。

但你是否真正理解:

  • keep-alive 缓存的是什么?
  • 它是如何实现的?
  • LRU 策略如何工作?

本文将从 源码级 深度解析 keep-alive 的核心机制。


一、keep-alive 是什么?

✅ 核心定义

keep-alive 是 Vue 的内置抽象组件,用于:

缓存动态组件或路由视图的实例,避免重复销毁与重建。

📌 基础用法

vue 复制代码
<!-- 缓存所有匹配的组件 -->
<keep-alive>
  <component :is="currentView"></component>
</keep-alive>

<!-- 或缓存路由视图 -->
<keep-alive>
  <router-view></router-view>
</keep-alive>

二、三大核心属性

属性 类型 说明
include `string RegExp
exclude `string RegExp
max `number string`

💡 实战示例

vue 复制代码
<keep-alive 
  include="UserInfo,OrderList"
  exclude="SearchResult"
  :max="10"
>
  <router-view />
</keep-alive>
  • ✅ 缓存 UserInfo 和 OrderList;
  • ❌ 不缓存 SearchResult;
  • ⚠️ 最多缓存 10 个实例,超出时按 LRU 策略清除。

三、keep-alive 如何工作?源码级解析

🧩 核心数据结构

js 复制代码
// 初始化缓存
created() {
  this.cache = Object.create(null); // 存储 { key: vnode }
  this.keys = []; // 存储 key,实现 LRU
}
  • cache: 缓存对象,key → vnode 映射;
  • keys: key 数组,记录访问顺序,实现 LRU(最近最少使用) 策略。

🔁 render 函数核心流程

步骤 1:获取第一个子组件

js 复制代码
const slot = this.$slots.default;
const vnode = getFirstComponentChild(slot);

💡 keep-alive 只对第一个子组件生效。


步骤 2:判断是否需要缓存

js 复制代码
const name = getComponentName(vnode.componentOptions);

// 不在 include 或在 exclude 中,直接返回
if (
  (include && !matches(include, name)) ||
  (exclude && matches(exclude, name))
) {
  return vnode;
}

步骤 3:生成唯一 key

js 复制代码
const key = vnode.key == null
  ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
  : vnode.key;

❗ 为什么不用 cid 唯一标识?

因为同一个构造函数可以注册为多个本地组件 ,cid 相同但组件不同。


步骤 4:缓存命中与 LRU 更新

js 复制代码
if (cache[key]) {
  // 命中缓存
  vnode.componentInstance = cache[key].componentInstance;
  
  // LRU:将 key 移到末尾(最新使用)
  remove(keys, key);
  keys.push(key);
} else {
  // 未命中,加入缓存
  cache[key] = vnode;
  keys.push(key);
  
  // 超出 max,清除最久未使用的
  if (max && keys.length > parseInt(max)) {
    pruneCacheEntry(cache, keys[0], keys);
  }
}

步骤 5:标记 keepAlive

js 复制代码
vnode.data.keepAlive = true;

这个标记告诉 Vue:跳过组件的 created、mounted 等生命周期。


四、缓存的是什么?真相揭秘

✅ 正确答案

keep-alive 缓存的是:

组件的 vnode 实例 和 componentInstance(组件实例)

包括:

  • 组件的 DOM 结构;
  • 组件的 data 状态;
  • 事件监听器;
  • 子组件树。

❌ 常见误解

  • ❌ 不是只缓存 HTML 字符串;
  • ❌ 不是只缓存 data 对象;
  • ❌ 不是"冻结"组件。

五、生命周期钩子:activated 与 deactivated

当组件被 keep-alive 包裹时,会新增两个生命周期钩子:

钩子 触发时机
activated 组件被激活(从缓存中显示)时调用
deactivated 组件被缓存(切换离开)时调用

💡 实战应用

js 复制代码
export default {
  data() {
    return {
      timer: null
    };
  },
  activated() {
    // 页面可见时恢复轮询
    this.timer = setInterval(() => {
      console.log('轮询中...');
    }, 1000);
  },
  deactivated() {
    // 页面隐藏时清除轮询,避免内存泄漏
    clearInterval(this.timer);
  }
}

六、首次渲染 vs 缓存渲染

📌 首次渲染

js 复制代码
init(vnode) {
  // 初次渲染,componentInstance 为 undefined
  const child = createComponentInstanceForVnode(vnode);
  child.$mount();
}
  • 正常执行 beforeCreate → created → mounted。

📌 缓存渲染

js 复制代码
init(vnode) {
  if (vnode.componentInstance && vnode.data.keepAlive) {
    // 直接复用实例,执行 prepatch
    componentVNodeHooks.prepatch(vnode, vnode);
  }
}
  • 跳过 created、mounted;
  • 直接将缓存的 DOM 插入文档;
  • 触发 activated 钩子。

七、LRU 缓存策略详解

📌 LRU(Least Recently Used)

"最近使用的,将来最可能再次使用。"

🔁 工作机制

操作 行为
新组件 插入 keys 数组末尾
命中缓存 将 key 从原位置移除,插入末尾
超出 max 移除 keys[0](最久未使用)

📊 示例:max=3

text 复制代码
操作: A → B → C → A → D
keys: [A] → [A,B] → [A,B,C] → [B,C,A] → [C,A,D]
  • D 加入时,B 被清除(最久未使用)。

八、最佳实践与避坑指南

✅ 最佳实践

  1. 合理设置 max:避免内存泄漏;
  2. 在 deactivated 中清理资源:定时器、事件监听;
  3. 使用 include 精准控制:避免缓存重型组件。

❌ 常见错误

  • 忘记给组件命名(name 选项);
  • 在 created 中启动轮询,未在 deactivated 中清除;
  • 缓存大量列表组件,导致内存飙升。

💡 结语

"keep-alive 是性能与体验的平衡艺术。"

要点 说明
缓存内容 vnode + 组件实例
核心机制 cache + keys + LRU
生命周期 activated / deactivated
适用场景 频繁切换的路由、表单、列表

掌握 keep-alive,你就能:

✅ 显著提升应用流畅度;

✅ 保留用户交互状态;

✅ 优化关键路径性能。

相关推荐
今年下半年1 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
郑州光合科技余经理1 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
前端snow3 小时前
ai agent --- DeepAgents 中间件
前端
data analyse 4564 小时前
报表能自定义的国内统计工具有哪些
前端·数据分析
IT_陈寒4 小时前
JavaScript闭包的这个坑,我居然今天才爬出来
前端·人工智能·后端
可乐鸡翅yeah_4 小时前
hls.js 切换多个视频源,新手开发常见踩坑
开发语言·前端·javascript·ios·ffmpeg·音视频·safari
葡萄城技术团队4 小时前
复制走的是数字,留下的是身份:Web 表格里被忽视的数据断层
前端
kyriewen4 小时前
我实测了前端日期的 5 个坑:差 8 小时只是开始
前端·javascript·程序员
测试运维日常笔记4 小时前
大模型应用专项测试指南:从 Prompt、RAG 到 Agent 的完整链路
前端·prompt