背景:在 b 端系統中,為了使用方便我們會在頁面設計中加上標籤頁類似瀏覽器上方標籤頁的功能,為了使用體驗更加接近瀏覽器標籤頁,我們需要針對路由進行快取。本文主要介紹 vue 專案針對不同業務場景如何利用 keep-alive 來實現標籤頁動態快取。keep-alive 是乙個抽象元件,不會和子元件建立父子關係,也不會作為節點渲染到頁面上。
關於抽象元件 vue 的文件沒有提這個概念,它有乙個屬性 abstract 為 true,在抽象元件的生命週期過程中,我們可以對包裹的子元件監聽的事件進行攔截,也可以對子元件進行 dom 操作,從而可以對我們需要的功能進行封裝,而不需要關心子元件的具體實現。除了kepp-alive還有等。keep-alive 的模式下多了 activated 這個生命週期函式, keep-alive 的宣告週期執行:
keep-alive 是由 render 函式決定渲染結果,在開頭會獲取插槽內的子元素,呼叫 getfirstcomponentchild 獲取到第乙個子元素的 vnode。
const slot = this.$slots.default
const vnode: vnode = getfirstcomponentchild(slot)
接著判斷當前元件是否符合快取條件,元件名與 include 不匹配或與 exclude 匹配都會直接退出並返回 vnode,不走快取機制。
// check pattern
const name: ?string = getcomponentname(componentoptions)
const = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
)
匹配條件通過會進入快取機制的邏輯,如果命中快取,從 cache 中獲取快取的例項設定到當前的元件上,並調整 key 的位置將其放到最後(lru 策略)。
如果沒命中快取,將當前 vnode 快取起來,並加入當前元件的 key。如果快取元件的數量超出 max 的值,即快取空間不足,則呼叫 prunecacheentry 將最舊的元件從快取中刪除,即 keys[0] 的元件。之後將元件的 keepalive 標記為 true,表示它是被快取的元件。
lru 快取策略:從記憶體中找出最久未使用的資料置換新的資料.演算法根據資料的歷史訪問記錄來進行淘汰資料,其核心思想是如果資料最近被訪問過,那麼將來被訪問的機率也更高。
const = this
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 ? `::$` : '')
: vnode.key
if (cache[key]) else
}
prunecacheentry 負責將元件從快取中刪除,它會呼叫元件 $destroy 方法銷毀元件例項,快取元件置空,並移除對應的 key。
function prunecacheentry (
cache: vnodecache,
key: string,
keys: array,
current?: vnode
) cache[key] = null
remove(keys, key)
}
一般採用在 router 的 meta 屬性裡增加乙個 keepalive 字段,然後在父元件或者根元件中,根據 keepalive 欄位的狀態使用 keep-alive 標籤,實現對路由的快取:
使用 vuex 配合 exclude 和 include,通過 include 和 exclude 決定那些元件進行快取。注意這裡說的是元件,並且 cachedview 陣列存放的是元件的名字,如下:
在 spa 應用中使用者希望在 tab 多個頁面來回切換的時候,不要丟失查詢的結果,關閉後清除快取。
如下圖:
期望是使用者在切換 tab 時 頁面時快取的,當使用者關閉 tab ,重新從左側選單開啟時是不快取。
這樣是持久快取了整個頁面,問題也就出現當使用者通過 tab 關閉頁面然後從左側開啟選單時是快取的頁面,這個不符合日常使用習慣,所以為了解決資料新鮮度的問題可以在 activated 觸發查詢請求就能保證資料的新鮮度。
activated()
但是使用後發現由於你切換 tab 時每次都會請求資料,但是如果專案的資料量有很大頻繁請求會給後端造成很大壓力 。
版本一需要頻繁拉去資料導致此方案已不合適只能動態快取元件方案。
其中 cachedviews 是通過監聽路由動態增加刪除維護要快取的元件名稱(所以元件名稱不要重複)陣列:
const state =
const mutations = ,
del_cached_view: (state, view) => ,
}const actions = , view) ,
deletecachedview(, view) ,
}export default
通過監聽路由變化:
watch: = newroute
const cacherout = this.iscache_map[name] ||
cacherout.map((item) => )
})},
},當通過 tab 關閉頁面時清除元件名稱:
closetag(newroute) = newroute
const cacherout = this.iscache_map[name] ||
cacherout.map((item) => )})}
但是在遇到巢狀路由時在層級不同的 router-view 中切換 tab 會出現快取資料失效的問題,無法快取元件,巢狀路由如下:
通過維護兩套資料,一套巢狀給左側選單,一套扁平化後註冊路由,改造後的路由:
通過上面 keep-alive 解析可以知道,keep-alive就是把通過 include 匹配的元件的 vnode,放到 keep-alive 元件的乙個 cache 物件中,下次渲染時,如果能在這裡面找到,就直接渲染vnode。所以把這個 cache 物件,放到全域性去(全域性變數或者 vuex),這樣我就可以不用快取 parnetview 也能快取其指定的子元件了。
import vue from 'vue'
const cache = {}
const keys =
export const removecachebyname = (name) =>
export default object.assign({}, vue.options.components.keepalive, ,
destroyed() {},
})
從上文可以知道 keep-alive 是從 cache 中獲取快取的例項設定到當前的元件上,key 是元件的名稱,可以通過改造 getcomponentname 方法,元件名稱獲取更改為路由名稱使其快取的對映關係只與 route name 值有關係。
function getcomponentname(opts)
cache 快取 key 也更改為路由名稱。
文|揣歪
關注得物技術,攜手走向技術的雲端
總結一下vue 得keepalive得實現原理
keep alive是vue得乙個內建元件,能將元件快取進記憶體,下次載入直接從記憶體中獲取。有2個屬性 include a 將快取元件名為a得元件 exclude a 元件名為a得不會被快取 注 元件名是 元件內內得name值 跟data同級 提供兩個生命週期 activated與deactiva...
keep alive實現原理
二 keep alive介紹與應用 2.1 keep alive是什麼 keep alive是乙個抽象元件 它自身不會渲染乙個dom元素,也不會出現在父元件鏈中 使用keep alive包裹動態元件時,會快取不活動的元件例項,而不是銷毀它們。乙個場景 使用者在某個列表頁面選擇篩選條件過濾出乙份資料列...
Keepalive工作原理
keepalived軟體起初是專為lvs負載均衡軟體設計的,用來管理並監控lvs集群系統中各個服務節點的狀態,後來又加入了可以實現高可用的vrrp功能。因此,keepalived除了能夠管理lvs軟體外,還可以作為其他服務 例如 nginx haproxy mysql等 的高可用解決方案軟體。kee...