Vue3源码解析--keep-alive
Vue3源码解析--keep-alive
YuXiang<keep-alive>
是 Vue 3 中一个非常重要的内置组件,用于缓存动态组件的状态,避免重复渲染和销毁。它通常用于优化性能,尤其是在需要频繁切换组件的场景(如标签页、路由切换等)。本文将从源码层面深入解析 <keep-alive>
的实现原理。
1. <keep-alive>
的基本用法
在 Vue 3 中,<keep-alive>
的使用方式如下:
1 | <template> |
<keep-alive>
包裹的动态组件会被缓存,当组件切换时,不会触发组件的销毁和重新创建。- 缓存的组件会保留其状态(如数据、DOM 状态等)。
2. <keep-alive>
的核心功能
<keep-alive>
的核心功能包括:
- 缓存组件实例:将动态组件的实例缓存起来,避免重复渲染。
- 生命周期钩子:提供 activated 和 deactivated 钩子,用于监听组件的激活和停用。
- LRU 缓存策略:通过 LRU(最近最少使用)算法管理缓存,防止内存泄漏。
3. 源码解析
Vue 3 的 <keep-alive>
源码位于 packages/runtime-core/src/components/KeepAlive.ts
。以下是其核心实现逻辑的解析。
3.1 组件定义
<keep-alive>
是一个函数式组件,其定义如下:
1 | export const KeepAliveImpl: ComponentOptions = { |
- include 和 exclude:用于控制哪些组件需要缓存。
- max:缓存的最大数量,超过时会使用 LRU 算法淘汰最久未使用的组件。
3.2 缓存管理
<keep-alive>
使用一个 Map 对象来缓存组件实例:
1 | const cache: Cache = new Map(); |
- cache:用于存储组件实例。
- keys:用于记录缓存组件的 key,用于实现 LRU 算法。
3.2.1 缓存组件
当组件被渲染时,<keep-alive>
会将其实例缓存起来:
1 | function cacheVNode(vnode: VNode) { |
- vnode.key:组件的唯一标识,用于区分不同的组件实例。
- 如果缓存数量超过 max,会淘汰最久未使用的组件。
3.2.2 淘汰策略
当缓存数量超过 max 时,<keep-alive>
会使用 LRU 算法淘汰最久未使用的组件:
1 | function pruneCacheEntry(key: CacheKey) { |
- unmount:卸载组件实例,触发其生命周期钩子deactivated。
3.3 生命周期钩子
<keep-alive>
通过劫持组件的生命周期钩子,实现了 activated 和 deactivated 钩子。
3.3.1 激活钩子(activated)
当缓存的组件被重新激活时,会触发 activated 钩子:
1 | function activate(vnode: VNode) { |
- vnode.component:组件的实例。
- activated:组件的激活钩子。
3.3.2 停用钩子(deactivated)
当缓存的组件被停用时,会触发 deactivated钩子:
1 | function deactivate(vnode: VNode) { |
- deactivated:组件的停用钩子。
3.4 渲染逻辑
<keep-alive>
的渲染逻辑主要通过 render 函数实现:
1 | function render() { |
- **slots.default()**:获取默认插槽的内容。
- vnode.shapeFlag:用于标记组件的类型和状态。
- 如果组件已经缓存,则直接从缓存中获取实例;否则,缓存新的组件实例。
4. 总结
<keep-alive>
的实现原理可以总结为以下几点:
- 缓存管理:通过 Map 对象缓存组件实例,并使用 LRU 算法管理缓存。
- 生命周期钩子:通过劫持组件的生命周期钩子,实现 activated 和 deactivated 钩子。
- 渲染逻辑:在渲染时,优先从缓存中获取组件实例,避免重复渲染。