面试之《vue keep-alive原理》

keep-alive 是 Vue.js 提供的一个内置组件,用于缓存动态组件,避免组件在切换时重复创建和销毁,从而提升应用的性能。下面详细介绍其缓存组件的原理:

整体原理概述

keep-alive 会在内部维护一个缓存对象(cache)和一个键(keys)数组。当组件被包裹在 keep-alive 中并首次渲染时,keep-alive 会将该组件实例缓存起来,并记录其对应的键。当再次需要渲染该组件时,keep-alive 会从缓存中取出该组件实例,而不是重新创建一个新的实例,这样就避免了组件的重新渲染,提高了性能。

详细工作流程

1. 初始化阶段

当 Vue 实例创建时,如果遇到 keep-alive 组件,会对其进行初始化。在这个过程中,会创建一个 cache 对象和一个 keys 数组,用于存储缓存的组件实例和对应的键。以下是简化的代码示例:

javascript 复制代码
export default {
  name: 'keep-alive',
  abstract: true, // 标记为抽象组件,不会渲染成真实 DOM
  data() {
    return {
      cache: Object.create(null),
      keys: []
    };
  },
  // ...
};
2. 渲染组件时

当 keep-alive 包裹的组件需要渲染时,会执行以下步骤:

  • 生成组件的键 :根据组件的 name 或 tag 等信息生成一个唯一的键。
  • 检查缓存 :检查 cache 对象中是否已经存在该键对应的组件实例。
    • 如果存在(命中缓存) :从 cache 中取出该组件实例,并将其对应的键移动到 keys 数组的末尾,表示该组件是最近使用的。然后直接使用缓存的组件实例进行渲染,跳过组件的创建和挂载过程。
    • 如果不存在(未命中缓存) :正常创建和挂载该组件实例,并将其缓存到 cache 对象中,同时将对应的键添加到 keys 数组中。如果 keys 数组的长度超过了 max 属性指定的最大缓存数量(如果设置了 max),则会移除 keys 数组中最旧的键对应的组件实例,以释放缓存空间。

以下是简化的渲染逻辑代码示例:

javascript 复制代码
render() {
  const vnode = getFirstComponentChild(this.$slots.default); // 获取第一个子组件
  const componentOptions = vnode && vnode.componentOptions;
  if (componentOptions) {
    const key = vnode.key == null
      ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
      : vnode.key;
    if (this.cache[key]) {
      // 命中缓存
      vnode.componentInstance = this.cache[key].componentInstance;
      // 将键移动到 keys 数组末尾
      remove(this.keys, key);
      this.keys.push(key);
    } else {
      // 未命中缓存
      this.cache[key] = vnode;
      this.keys.push(key);
      // 检查是否超过最大缓存数量
      if (this.max && this.keys.length > parseInt(this.max)) {
        pruneCacheEntry(this.cache, this.keys[0], this.keys, this._vnode);
      }
    }
  }
  return vnode;
}
3. 组件销毁时

当 keep-alive 包裹的组件被移除时,由于组件被缓存了,并不会真正销毁,而是进入一种"停用"状态。此时,组件的 deactivated 生命周期钩子会被调用。当再次渲染该组件时,会进入"激活"状态,组件的 activated 生命周期钩子会被调用。

总结

keep-alive 通过维护一个缓存对象和键数组,实现了组件的缓存和复用。在组件渲染时,优先从缓存中获取组件实例,避免了重复创建和销毁,同时利用 activated 和 deactivated 生命周期钩子来处理组件的激活和停用状态,从而提升了应用的性能和用户体验。

相关推荐
wo_jack12 小时前
C++ 入门笔记(十六):第16课 vector 模拟实现十问十答 —— 从三指针到迭代器失效
c++·后端·面试·stl·vector
FRing0313 小时前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
聪明的笨猪猪14 小时前
AI应用架构选型:架构师的核心决策困境与权衡
经验分享·面试·架构
疯华整猫16 小时前
被杀掉之后:我把 Android 的「唤起 + 常驻」重做了一遍
前端·面试·架构
ruanno_top17 小时前
点全选,已选的被清空了:Transfer 三态复选框的三个 bug
vue.js
nice_lcj52017 小时前
Java 并发容器入门:ConcurrentHashMap、CopyOnWriteArrayList、阻塞队列
java·面试·并发编程·阻塞队列·concurrenthashmap·copyonwritearraylist
时间的情敌18 小时前
Cesium 加载 3D Tiles 倾斜摄影、压平、样式设置(Vue3 实战)
vue.js·3d·cesium
岁月宁静1 天前
AI 应用开发工程师简历怎么写:HR 初筛、技术复筛、面试追问,三道关卡各看什么?
人工智能·python·面试
Dream it possible!1 天前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
Pniubi1 天前
力扣560.和为k的子数组
算法·leetcode·职场和发展