第 24 题:说一下 Vue3 的 keep-alive 原理?缓存是怎么做的?
一、核心回答(面试最想听的版本)
<keep-alive> 是 Vue3 的一个内置组件,用来缓存 组件的实例,避免组件被销毁,提升性能。
其原理:
-
首次渲染 :创建组件实例并缓存到
cache(Map)。 -
再次切换回组件 :直接从缓存里取实例,不会重新执行
setup,不会重新挂载 DOM。 -
失活激活机制:不是销毁,而是触发:
onDeactivated(组件失活)onActivated(重新激活)
-
LRU 策略(基于 max 属性):
- 缓存超出数量,会移除最久未访问的组件。
二、keep-alive 的详细原理(深度版,让面试官觉得你懂底层)
🔹 1. keep-alive 内部实现一个 Map 做缓存
javascript
const cache = new Map()
- key:组件唯一 ID(VNode.type)
- value:组件实例 + DOM 节点
🔹 2. 渲染过程
当 keep-alive 渲染一个组件:
如果 cache 里没有
→ 创建新的组件实例 → 渲染 → 缓存到 cache
如果 cache 里已经有
→ 直接复用之前缓存的实例(VNode),跳过组件初始化
🔹 3. 缓存命中后的激活过程
复用时不会走 setup()
只会调用:
scss
onActivated(() => {
// DOM 被插回时触发
})
🔹 4. 切换路由离开时不会卸载组件
不会执行 onUnmounted
改成:
scss
onDeactivated(() => {
// DOM 被移出容器时触发
})
🔹 5. LRU 机制(max 属性)
如果你写:
ini
<keep-alive :max="2">
keep-alive 会:
- 最多缓存 2 个组件
- 超出时从 cache 中删最老的一个(LRU)
实现伪代码:
scss
if (cache.size > max) {
const oldestKey = cache.keys().next().value
pruneCacheEntry(oldestKey)
}
三、常见用法
✔ 缓存路由组件:
xml
<keep-alive>
<router-view />
</keep-alive>
✔ include / exclude 精准控制缓存
ini
<keep-alive include="UserList,UserInfo" exclude="LoginPage">
✔ 动态缓存:
xml
<keep-alive :include="cachedComponents">
<router-view />
</keep-alive>
四、常见面试追问 + 你该怎么回答
❓1. keep-alive 和 v-if 的区别?
✔ v-if 会销毁组件
✔ keep-alive 只是隐藏,不销毁
keep-alive 是"组件级缓存",v-if 是"条件渲染控制"
❓2. keep-alive 缓存哪些内容?
缓存的是:
- 组件实例(setup 返回值)
- 响应式状态
- DOM 节点
不会缓存:
- props 变化后的新状态(需要手动 watch)
- DOM 外部依赖(scroll 位置、定时器等)
❓3. keep-alive 配合 router-view 为什么有时失效?
常见原因:
- 没有设置
router-view的name - dynamic import 组件 name 不对
- 不正确使用 include / exclude
❓4. 如何强制清理 keep-alive 缓存?
可使用 key:
ruby
<router-view :key="$route.fullPath"/>
或利用 include/exclude 动态控制。
五、面试官想听的总结(高分版)
keep-alive 本质是用 Map 缓存组件实例,通过激活与失活控制组件挂载状态,并通过 LRU 算法管理缓存数量。
常用于路由缓存、tab 页签、复杂组件反复切换的性能优化。