中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

keep-alive組件的緩存原理是什么

發布時間:2021-01-18 14:39:07 來源:億速云 閱讀:673 作者:Leah 欄目:開發技術

本篇文章為大家展示了keep-alive組件的緩存原理是什么,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

官方API介紹和用法

  • <keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。

  • 和 <transition> 相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在組件的父組件鏈中。

  • 當組件在 <keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命周期鉤子函數將會被對應執行。

官網的例子是 tab 切換保存了用戶的操作,實際中還可能遇到從列表頁跳轉去了詳情頁,再跳轉回列表頁需要保存用戶進行過的篩選操作,這就需要用到 <keep-alive>,這樣也能避免重新渲染,提高頁面性能。

用法及props的講解

// keep-alive組件搭配動態組件的用法,還要其他的用法參見官網
<keep-alive
 include="['componentNameA', 'componentNameB']"
 exclude="'componentNameC'"
 :max="10">
 <component :is="view"></component>
</keep-alive>
  • include - 字符串或正則表達式或數組,name匹配上的組件會被緩存

  • exclude - 字符串或正則表達式或數組,name匹配上的組件都不會被緩存

  • max - 字符串或數字,緩存組件實例的最大數,最久沒有被訪問的實例會被銷毀掉

注意:

  • <keep-alive> 只渲染其直系的一個組件,因此若在 <keep-alive> 中用 v-for,則其不會工作,若多條件判斷有多個符合條件也同理不工作。

  • include 和 exclude 匹配時,首先檢查組件的 name 選項,若 name 選項不可用,則匹配它的局部注冊名稱 (即父組件 components 選項的鍵值)。匿名組件不能被匹配。

  • <keep-alive> 不會在函數式組件中正常工作,因為它們沒有緩存實例。

源碼解讀

先貼一張源碼圖

keep-alive組件的緩存原理是什么

總共125行,收起來一看其實東西也比較少。前面是引入一些需要用到的方法,然后定義了一些  keep-alive 組件自己會用到的一些方法,最后就是向外暴露一個 name 為 keep-alive 的組件選項,這些選項除了 abstract 外,其他的我們都比較熟悉了,其中, render 函數就是緩存原理最重要的部分,也能看出 keep-alive 組件是一個函數式組件。

// isRegExp函數判斷是不是正則表達式,remove移除數組中的某一個成員
// getFirstComponentChild獲取VNode數組的第一個有效組件
import { isRegExp, remove } from 'shared/util'
import { getFirstComponentChild } from 'core/vdom/helpers/index'

type VNodeCache = { [key: string]: ?VNode }; // 緩存組件VNode的緩存類型

// 通過組件的name或組件tag來獲取組件名(上面注意的第二點)
function getComponentName (opts: ?VNodeComponentOptions): ?string {
 return opts && (opts.Ctor.options.name || opts.tag)
}

// 判斷include或exclude跟組件的name是否匹配成功
function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
 if (Array.isArray(pattern)) {
 return pattern.indexOf(name) > -1 // include或exclude是數組的情況
 } else if (typeof pattern === 'string') {
 return pattern.split(',').indexOf(name) > -1 // include或exclude是字符串的情況
 } else if (isRegExp(pattern)) {
 return pattern.test(name) // include或exclude是正則表達式的情況
 }
 return false // 都沒匹配上(上面注意的二三點)
}

// 銷毀緩存
function pruneCache (keepAliveInstance: any, filter: Function) {
 const { cache, keys, _vnode } = keepAliveInstance // keep-alive組件實例
 for (const key in cache) {
 const cachedNode: ?VNode = cache[key] // 已經被緩存的組件
 if (cachedNode) {
  const name: ?string = getComponentName(cachedNode.componentOptions)
  // 若name存在且不能跟include或exclude匹配上就銷毀這個已經緩存的組件
  if (name && !filter(name)) {
  pruneCacheEntry(cache, key, keys, _vnode)
  }
 }
 }
}

// 銷毀緩存的入口
function pruneCacheEntry (
 cache: VNodeCache,
 key: string,
 keys: Array<string>,
 current?: VNode
) {
 const cached = cache[key] // 被緩存過的組件
 // “已經被緩存的組件是否繼續被緩存” 有變動時
 // 若組件被緩存命中過且當前組件不存在或緩存命中組件的tag和當前組件的tag不相等
 if (cached && (!current || cached.tag !== current.tag)) {
 // 說明現在這個組件不需要被繼續緩存,銷毀這個組件實例
 cached.componentInstance.$destroy()
 }
 cache[key] = null // 把緩存中這個組件置為null
 remove(keys, key) // 把這個組件的key移除出keys數組
}

// 示例類型
const patternTypes: Array<Function> = [String, RegExp, Array]

// 向外暴露keep-alive組件的一些選項
export default {
 name: 'keep-alive', // 組件名
 abstract: true, // keep-alive是抽象組件

 // 用keep-alive組件時傳入的三個props
 props: {
 include: patternTypes,
 exclude: patternTypes,
 max: [String, Number]
 },

 created () {
 this.cache = Object.create(null) // 存儲需要緩存的組件
 this.keys = [] // 存儲每個需要緩存的組件的key,即對應this.cache對象中的鍵值
 },

 // 銷毀keep-alive組件的時候,對緩存中的每個組件執行銷毀
 destroyed () {
 for (const key in this.cache) {
  pruneCacheEntry(this.cache, key, this.keys)
 }
 },

 // keep-alive組件掛載時監聽include和exclude的變化,條件滿足時就銷毀已緩存的組件
 mounted () {
 this.$watch('include', val => {
  pruneCache(this, name => matches(val, name))
 })
 this.$watch('exclude', val => {
  pruneCache(this, name => !matches(val, name))
 })
 },

 // 重點來了
 render () {
 const slot = this.$slots.default // keep-alive組件的默認插槽
 const vnode: VNode = getFirstComponentChild(slot) // 獲取默認插槽的第一個有效組件
 // 如果vnode存在就取vnode的選項
 const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
 if (componentOptions) {
  //獲取第一個有效組件的name
  const name: ?string = getComponentName(componentOptions)
  const { include, exclude } = this // props傳遞來的include和exclude
  if (
  // 若include存在且name不存在或name未匹配上
  (include && (!name || !matches(include, name))) ||
  // 若exclude存在且name存在或name匹配上
  (exclude && name && matches(exclude, name))
  ) {
  return vnode // 說明不用緩存,直接返回這個組件進行渲染
  }
  
  // 匹配上就需要進行緩存操作
  const { cache, keys } = this // keep-alive組件的緩存組件和緩存組件對應的key
  // 獲取第一個有效組件的key
  const key: ?string = vnode.key == null
  // 同一個構造函數可以注冊為不同的本地組件
  // 所以僅靠cid是不夠的,進行拼接一下
  ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
  : vnode.key
  // 如果這個組件命中緩存
  if (cache[key]) {
  // 這個組件的實例用緩存中的組件實例替換
  vnode.componentInstance = cache[key].componentInstance
  // 更新當前key在keys中的位置
  remove(keys, key) // 把當前key從keys中移除
  keys.push(key) // 再放到keys的末尾
  } else {
  // 如果沒有命中緩存,就把這個組件加入緩存中
  cache[key] = vnode
  keys.push(key) // 把這個組件的key放到keys的末尾
  // 如果緩存中的組件個數超過傳入的max,銷毀緩存中的LRU組件
  if (this.max && keys.length > parseInt(this.max)) {
   pruneCacheEntry(cache, keys[0], keys, this._vnode)
  }
  }

  vnode.data.keepAlive = true // 設置這個組件的keepAlive屬性為true
 }
 // 若第一個有效的組件存在,但其componentOptions不存在,就返回這個組件進行渲染
 // 或若也不存在有效的第一個組件,但keep-alive組件的默認插槽存在,就返回默認插槽的第一個組件進行渲染
 return vnode || (slot && slot[0])
 }
}

上述內容就是keep-alive組件的緩存原理是什么,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安岳县| 静安区| 万年县| 顺义区| 福海县| 简阳市| 吴忠市| 当阳市| 山西省| 祁阳县| 阜宁县| 陆丰市| 永昌县| 廉江市| 延长县| 怀来县| 定远县| 铜梁县| 蒲城县| 永济市| 定兴县| 秀山| 奎屯市| 永仁县| 宁强县| 贺州市| 金堂县| 遂川县| 阿拉善盟| 宝坻区| 仁寿县| 东平县| 崇信县| 鹤壁市| 龙游县| 城步| 济宁市| 兰溪市| 双辽市| 理塘县| 班玛县|