1. 程式人生 > 程式設計 >LRU演算法在Vue內建元件keep-alive中的使用

LRU演算法在Vue內建元件keep-alive中的使用

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",name => !matches(val,name));
    });
  },render() {
    // 獲取第一個子元素的 vnode
    const slot = this.$slots.default;
    const vnode: VNode = getFirstComponentChild(slot);
    const componentOptions: ?VNodeComponentOptions =
      vnode &http://www.cppcns.com
;& 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 && namQyQxyL
e && 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); } } QyQxyL
// 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) /** * Remove an item from an array. */ 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 http://www.cppcns.com(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);
        this.doubleList = new DoubleList(node,node);
    }
    
    /**
     * 獲取快取值
     * 不存在返回-1,存在返回對應value值,並將此節點移到尾巴
     * @param {*} key  key值
     */
    get(key){
        let node = this.map.get(key)
        if(!node){
            return -1;
        }else{
            this.moveNode2Tail(key,node);
            return node.value;
        }
    }

    /**
     * 插入快取
     * 1.不存在對應key值,加到尾巴
     * 2.存在對應key值,更新此key值對應value並提到尾巴
     * 3.超出容量的話,去掉頭部資料
     * @param {*} key  key值
     * @param {*} value  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,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,node.value,newNode);
    }
}

以上就是LRU演算法在Vue內建元件keep-alive中的使用的詳細內容,更多關於Vue LRU演算法的資料請關注我們其它相關文章!