LRU算法在Vue內(nèi)置組件keep-alive中的使用
vue的keep-alive內(nèi)置組件的使用也是使用了改算法,源碼如下:
export default { name: "keep-alive", // 抽象組件屬性 ,它在組件實(shí)例建立父子關(guān)系的時(shí)候會(huì)被忽略,發(fā)生在 initLifecycle 的過(guò)程中 abstract: true, props: { // 被緩存組件 include: patternTypes, // 不被緩存組件 exclude: patternTypes, // 指定緩存大小 max: [String, Number] }, created() { // 初始化用于存儲(chǔ)緩存的 cache 對(duì)象 this.cache = Object.create(null); // 初始化用于存儲(chǔ)VNode key值的 keys 數(shù)組 this.keys = []; }, destroyed() { for (const key in this.cache) { // 刪除所有緩存 pruneCacheEntry(this.cache, key, this.keys); } }, mounted() { // 監(jiān)聽(tīng)緩存(include)/不緩存(exclude)組件的變化 // 在變化時(shí),重新調(diào)整 cache // pruneCache:遍歷 cache,如果緩存的節(jié)點(diǎn)名稱(chēng)與傳入的規(guī)則沒(méi)有匹配上的話(huà),就把這個(gè)節(jié)點(diǎn)從緩存中移除 this.$watch("include", val => { pruneCache(this, name => matches(val, name)); }); this.$watch("exclude", val => { pruneCache(this, name => !matches(val, name)); }); }, render() { // 獲取第一個(gè)子元素的 vnode const slot = this.$slots.default; const vnode: VNode = getFirstComponentChild(slot); const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions; if (componentOptions) { // name 不在 inlcude 中或者在 exlude 中則直接返回 vnode,否則繼續(xù)進(jìn)行下一步 // 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; // 獲取鍵,優(yōu)先獲取組件的 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 算法了, // 如果在緩存里有則調(diào)整, // 沒(méi)有則放入(長(zhǎng)度超過(guò) max,則淘汰最近沒(méi)有訪(fǎng)問(wèn)的) // -------------------------------------------------- // 如果命中緩存,則從緩存中獲取 vnode 的組件實(shí)例,并且調(diào)整 key 的順序放入 keys 數(shù)組的末尾 if (cache[key]) { vnode.componentInstance = cache[key].componentInstance; // make current key freshest remove(keys, key); keys.push(key); } // 如果沒(méi)有命中緩存,就把 vnode 放進(jìn)緩存 else { cache[key] = vnode; keys.push(key); // prune oldest entry // 如果配置了 max 并且緩存的長(zhǎng)度超過(guò)了 this.max,還要從緩存中刪除第一個(gè) if (this.max && keys.length > parseInt(this.max)) { pruneCacheEntry(cache, keys[0], keys, this._vnode); } } // keepAlive標(biāo)記位 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) } } }
實(shí)現(xiàn)一個(gè)自己的LRU算法
lru算法 的核心api(put get)和一個(gè)size最大容器值,本質(zhì)是類(lèi)似隊(duì)列 put實(shí)現(xiàn)思路 1 是否存在,存在就先刪除,再添加到隊(duì)頭 2 不存在,容量是否滿(mǎn)了,刪除最后一個(gè)隊(duì)尾,再添加隊(duì)頭 get實(shí)現(xiàn)思路: 1.有就返回,同時(shí)插入隊(duì)頭 2.沒(méi)有返回-1 時(shí)間復(fù)雜度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 { //不存在,容量是否滿(mǎn)了 if (this.size === this.cache.size) { //刪除最后一個(gè) this.cache.delete(this.cache.keys().next().value) //拿到隊(duì)尾的元素 } } //插在隊(duì)頭 this.cache.set(key, val) } get (key) { let val = this.cache.get(key) if (!val) { return -1 } //訪(fǎng)問(wèn)了就需要放在隊(duì)頭 this.put(key, val) return val } }
另一種
//定義節(jié)點(diǎn)類(lèi) 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 { //構(gòu)造函數(shù),傳入緩存容量 constructor(max){ this.max = max; this.map = new Map(); let node = new Node(null, null, null, null); this.doubleList = new DoubleList(node, node); } /** * 獲取緩存值 * 不存在返回-1,存在返回對(duì)應(yīng)value值,并將此節(jié)點(diǎn)移到尾巴 * @param {*} key key值 */ get(key){ let node = this.map.get(key) if(!node){ return -1; }else{ this.moveNode2Tail(key, node); return node.value; } } /** * 插入緩存 * 1.不存在對(duì)應(yīng)key值,加到尾巴 * 2.存在對(duì)應(yīng)key值,更新此key值對(duì)應(yīng)value并提到尾巴 * 3.超出容量的話(huà),去掉頭部數(shù)據(jù) * @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, 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; } } //將節(jié)點(diǎn)移到尾巴 moveNode2Tail(key,node){ if(!node.next){ return; } //刪除節(jié)點(diǎn) node.pre.next = node.next; node.next.pre = node.pre; this.map.delete(key) //新增尾巴節(jié)點(diǎn) 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內(nèi)置組件keep-alive中的使用的詳細(xì)內(nèi)容,更多關(guān)于Vue LRU算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
用vue 實(shí)現(xiàn)手機(jī)觸屏滑動(dòng)功能
這篇文章主要介紹了用vue 實(shí)現(xiàn)手機(jī)觸屏滑動(dòng)的功能,文中通過(guò)示例代碼給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05VUE中攔截請(qǐng)求并無(wú)感知刷新token方式
這篇文章主要介紹了VUE中攔截請(qǐng)求并無(wú)感知刷新token方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08使用Vue+MySQL實(shí)現(xiàn)登錄注冊(cè)的實(shí)戰(zhàn)案例
第一次用Vue+MySQL實(shí)現(xiàn)注冊(cè)登錄功能,就已經(jīng)踩了很多坑,下面這篇文章主要給大家介紹了關(guān)于使用Vue+MySQL實(shí)現(xiàn)登錄注冊(cè)案例的相關(guān)資料,需要的朋友可以參考下2022-05-05Vue使用三方工具vueUse實(shí)現(xiàn)虛擬列表
其實(shí)采用vueUse中的useVirtualList方法同樣可以實(shí)現(xiàn)虛擬列表,這篇文章小編就來(lái)和大家詳細(xì)介紹一下如何使用vueUse實(shí)現(xiàn)簡(jiǎn)單的虛擬列表效果吧2024-04-04vue實(shí)現(xiàn)購(gòu)物車(chē)加減
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)購(gòu)物車(chē)加減,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05vue3動(dòng)態(tài)加載對(duì)話(huà)框的方法實(shí)例
對(duì)話(huà)框是很常用的組件,在很多地方都會(huì)用到,下面這篇文章主要給大家介紹了關(guān)于vue3動(dòng)態(tài)加載對(duì)話(huà)框的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03Vue-cli3生成的Vue項(xiàng)目加載Mxgraph方法示例
這篇文章主要介紹了Vue-cli3生成的Vue項(xiàng)目加載Mxgraph方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Vue頁(yè)面刷新記住頁(yè)面狀態(tài)的實(shí)現(xiàn)
這篇文章主要介紹了Vue頁(yè)面刷新記住頁(yè)面狀態(tài)的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-12-12