文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

LRU算法在Vue内置组件keep-alive中的使用

2024-04-02 19:55

关注

vue的keep-alive内置组件的使用也是使用了改算法,源码如下:


export default {
  name: "keep-alive",
  // 抽象组件属性 ,它在组件实例建立父子关系的时候会被忽略,发生在 initLifecycle 的过程中
  abstract: true, 
  props: {
    // 被缓存组件
    include: patternTypes, 
    // 不被缓存组件
    exclude: patternTypes,
    // 指定缓存大小
    max: [String, Number] 
  },
  created() {
    // 初始化用于存储缓存的 cache 对象
    this.cache = Object.create(null);
    // 初始化用于存储VNode key值的 keys 数组
    this.keys = []; 
  },
  destroyed() {
    for (const key in this.cache) {
      // 删除所有缓存
      pruneCacheEntry(this.cache, key, this.keys);
    }
  },
  mounted() {
    // 监听缓存(include)/不缓存(exclude)组件的变化
    // 在变化时,重新调整 cache
    // pruneCache:遍历 cache,如果缓存的节点名称与传入的规则没有匹配上的话,就把这个节点从缓存中移除
    this.$watch("include", val => {
      pruneCache(this, name => matches(val, name));
    });
    this.$watch("exclude", val => {
      pruneCache(this, name => !matches(val, name));
    });
  },
  render() {
    // 获取第一个子元素的 vnode
    const slot = this.$slots.default;
    const vnode: VNode = getFirstComponentChild(slot);
    const componentOptions: ?VNodeComponentOptions =
      vnode && vnode.componentOptions;
    if (componentOptions) {
      // name 不在 inlcude 中或者在 exlude 中则直接返回 vnode,否则继续进行下一步
      // check pattern
      const name: ?string = getComponentName(componentOptions);
      const { include, exclude } = this;
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode;
      }
      
      const { cache, keys } = this;
      // 获取键,优先获取组件的 name 字段,否则是组件的 tag
      const key: ?string =
        vnode.key == null
          ? // same constructor may get registered as different local components
            // so cid alone is not enough (#3269)
            componentOptions.Ctor.cid +
            (componentOptions.tag ? `::${componentOptions.tag}` : "")
          : vnode.key;
        
      // --------------------------------------------------
      // 下面就是 LRU 算法了,
      // 如果在缓存里有则调整,
      // 没有则放入(长度超过 max,则淘汰最近没有访问的)
      // --------------------------------------------------
      // 如果命中缓存,则从缓存中获取 vnode 的组件实例,并且调整 key 的顺序放入 keys 数组的末尾
      if (cache[key]) {
        vnode.componentInstance = cache[key].componentInstance;
        // make current key freshest
        remove(keys, key);
        keys.push(key);
      }
      // 如果没有命中缓存,就把 vnode 放进缓存
      else {
        cache[key] = vnode;
        keys.push(key);
        // prune oldest entry
        // 如果配置了 max 并且缓存的长度超过了 this.max,还要从缓存中删除第一个
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode);
        }
      }
      
      // keepAlive标记位
      vnode.data.keepAlive = true;
    }
    return vnode || (slot && slot[0]);
  }
};

// 移除 key 缓存
function pruneCacheEntry (
  cache: VNodeCache,
  key: string,
  keys: Array<string>,
  current?: VNode
) {
  const cached = cache[key]
  if (cached && (!current || cached.tag !== current.tag)) {
    cached.componentInstance.$destroy()
  }
  cache[key] = null
  remove(keys, key)
}

// remove 方法(shared/util.js)

export function remove (arr: Array<any>, item: any): Array<any> | void {
  if (arr.length) {
    const index = arr.indexOf(item)
    if (index > -1) {
      return arr.splice(index, 1)
    }
  }
}

实现一个自己的LRU算法

lru算法 的核心api(put get)和一个size最大容器值,本质是类似队列 put实现思路 1 是否存在,存在就先删除,再添加到队头 2 不存在,容量是否满了,删除最后一个队尾,再添加队头 get实现思路: 1.有就返回,同时插入队头 2.没有返回-1 时间复杂度O(1)


class LRU {
  constructor(size) {
    this.cache = new Map()
    this.size = size
  }
  put (key, val) {
    //存在
    if (this.cache.has(key)) {
      //删除
      this.cache.delete(key)
    } else {
      //不存在,容量是否满了
      if (this.size === this.cache.size) {
        //删除最后一个
        this.cache.delete(this.cache.keys().next().value) //拿到队尾的元素
      }
    }
    //插在队头
    this.cache.set(key, val)
  }
  get (key) {
    let val = this.cache.get(key)
    if (!val) {
      return -1
    }
    //访问了就需要放在队头
    this.put(key, val)
    return val
  }
}

另一种


//定义节点类
class Node {
    constructor(pre, next, value, key){
        this.pre = pre;
        this.next = next;
        this.value = value;
        this.key = key;
    }
}

//定义双向链表
class DoubleList {
    constructor(head, tail){
        this.head = head;
        this.tail = tail;
    }
}


class LRUCache {
    //构造函数,传入缓存容量
    constructor(max){
        this.max = max;
        this.map = new Map();
        let node = new Node(null, null, null, null);
        this.doubleList = new DoubleList(node, node);
    }
    
    
    get(key){
        let node = this.map.get(key)
        if(!node){
            return -1;
        }else{
            this.moveNode2Tail(key, node);
            return node.value;
        }
    }

    
    put(key, value) {
        let node = this.map.get(key);
        if(node){
            if(!node.next){
                node.value = value;
                return;
            }
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
        let newNode = new Node(null, null, value, key);
        newNode.pre = this.doubleList.tail;
        this.doubleList.tail.next = newNode;
        this.doubleList.tail = newNode;
        this.map.set(key, newNode);
        if(this.map.size > this.max){
            this.map.delete(this.doubleList.head.next.key);
            this.doubleList.head.next = this.doubleList.head.next.next;
            this.doubleList.head.next.pre = this.doubleList.head;          
        }
    }
    
    //将节点移到尾巴
    moveNode2Tail(key,node){   
        if(!node.next){
            return;
        }
        //删除节点   
        node.pre.next = node.next;
        node.next.pre = node.pre;
        this.map.delete(key)
        //新增尾巴节点
        let newNode = new Node(null, null, node.value, key);
        newNode.pre = this.doubleList.tail;
        this.doubleList.tail.next = newNode;
        this.doubleList.tail = newNode;
        this.map.set(key, newNode);
    }
}

以上就是LRU算法在Vue内置组件keep-alive中的使用的详细内容,更多关于Vue LRU算法的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯