Skip to content

算法实现

js
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }

  get(key) {
    let item = this.cache.get(key);
    if (!item) {
      return -1;
    }
    this.cache.delete(key);
    this.cache.set(key, item);
    return item;
  }

  set(key, value) {
    let item = this.cache.get(key);
    if (item) {
      this.cache.delete(key);
    }
    if (this.cache.size() === this.capacity) {
      // 删除最后一个
      const oldestKey = this.cache.keys()[0];
      this.cache.delete(oldestKey);
    }
    this.cache.set(key, value);
  }
}
//注: JavaScript 的 Map 天然维护插入顺序,可简化实现

Vue 的 KeepAlive 实现

Vue(2.x)源码简化

js
export default {
  name: "keep-alive",
  abstract: true, // 抽象组件,不渲染真实 DOM
  props: {
    include: [String, RegExp, Array], // 需缓存的组件
    exclude: [String, RegExp, Array], // 不缓存的组件
    max: [Number, String], // 最大缓存数量
  },
  created() {
    this.cache = Object.create(null); // 缓存组件实例:{ key: vnode }
    this.keys = []; // 记录缓存顺序(用于 LRU)
  },
  destroyed() {
    // 销毁时清空所有缓存
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys);
    }
  },
  mounted() {
    // 监听 include/exclude 变化,更新缓存
    this.$watch("include", (val) => {
      pruneCache(this, (name) => matches(val, name));
    });
    this.$watch("exclude", (val) => {
      pruneCache(this, (name) => !matches(val, name));
    });
  },
  render() {
    // ... 省略获取子组件 vnode 的逻辑 ...
    const key =
      vnode.key ||
      componentOptions.Ctor.cid +
        (componentOptions.tag ? `::${componentOptions.tag}` : "");

    // 若已缓存,直接复用
    if (this.cache[key]) {
      vnode.componentInstance = this.cache[key].componentInstance;
      // 刷新 key 位置(移到末尾,标记为“最近使用”)
      this.keys.splice(this.keys.indexOf(key), 1);
      this.keys.push(key);
    }
    // 未缓存且需缓存
    else if (shouldCache) {
      this.cache[key] = vnode;
      this.keys.push(key);
      // 超过 max,删除最久未使用的(keys[0])
      if (this.max && this.keys.length > parseInt(this.max)) {
        pruneCacheEntry(this.cache, this.keys[0], this.keys);
      }
    }

    return vnode;
  },
};

总结

  • LRU 是一种 “淘汰最近最少使用项” 的缓存策略,通过 “哈希表 + 双向链表” 实现高效访问和更新。
  • Vue 的 keep-alive 基于 LRU 策略缓存组件实例,减少频繁切换时的性能损耗,核心是 cache 缓存实例、keys 维护顺序,并通过 max 触发 LRU 淘汰。

Released under the MIT License.