国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - vue.js - 從源碼角度來回答keep-alive組件的緩存原理

從源碼角度來回答keep-alive組件的緩存原理

2022-01-04 16:26十八喲 vue.js

這篇文章主要介紹了從源碼角度來回答keep-alive組件的緩存原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

今天開門見山地聊一下面試中被問到的一個問題:keep-alive組件的緩存原理。

官方API介紹和用法

  • <keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。
  • 和 <transition> 相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在組件的父組件鏈中。
  • 當組件在 <keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命周期鉤子函數將會被對應執行。

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

用法及props的講解

?
1
2
3
4
5
6
7
// 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 組件是一個函數式組件。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 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])
 }
}

補充:

上面關于刪除第一個舊緩存組件和更新緩存組件 key 的順序,其實是用到了LRU緩存淘汰策略:
LRU全稱Least Recently Used,最近最少使用的意思,是一種內存管理算法。
這種算法基于一種假設:長期不用的數據,在未來被用到的幾率也很小,因此,當數據所占內存達到一定閾值,可以移除掉最近最少使用的。

總結

簡單總結為:

keep-alive 組件在渲染的時候,會根據傳入的 include 和 exclude 來匹配 keep-alive 包裹的命名組件,未匹配上就直接返回這個命名組件進行渲染,若匹配上就進行緩存操作:若緩存中已有這個組件,就替換其實例,并更新這個組件的 key 在 keys 中的位置;若緩存中沒有這個組件,就把這個組件放入 keep-alive 組件的緩存 cache 中,并把這個組件的 key 放入 keys 中,由于在 mounted 的時候有對 include 和 exclude 進行監聽,因此,后續這兩個屬性值發生變化時,會再次判斷是否滿足條件而進行組件銷毀。

到此這篇關于從源碼角度來回答keep-alive組件的緩存原理的文章就介紹到這了,更多相關keep-alive組件緩存內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://juejin.cn/post/6918569473419165709

延伸 · 閱讀

精彩推薦
  • vue.jsVue2.x 項目性能優化之代碼優化的實現

    Vue2.x 項目性能優化之代碼優化的實現

    這篇文章主要介紹了Vue2.x 項目性能優化之代碼優化的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    優小U9632022-02-21
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看過很多人講vue的生命周期,但總是被繞的云里霧里,尤其是自學的同學,可能js的基礎也不是太牢固,聽起來更是吃力,那我就已個人之淺見,以大白話...

    CRMEB技術團隊7992021-12-22
  • vue.jsVue多選列表組件深入詳解

    Vue多選列表組件深入詳解

    這篇文章主要介紹了Vue多選列表組件深入詳解,這個是vue的基本組件,有需要的同學可以研究下...

    yukiwu6752022-01-25
  • vue.jsVue項目中實現帶參跳轉功能

    Vue項目中實現帶參跳轉功能

    最近做了一個手機端系統,其中遇到了父頁面需要攜帶參數跳轉至子頁面的問題,現已解決,下面分享一下實現過程,感興趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.js用vite搭建vue3應用的實現方法

    用vite搭建vue3應用的實現方法

    這篇文章主要介紹了用vite搭建vue3應用的實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下...

    Asiter7912022-01-22
  • vue.jsVue中引入svg圖標的兩種方式

    Vue中引入svg圖標的兩種方式

    這篇文章主要給大家介紹了關于Vue中引入svg圖標的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    十里不故夢10222021-12-31
  • vue.js詳解vue 表單綁定與組件

    詳解vue 表單綁定與組件

    這篇文章主要介紹了vue 表單綁定與組件的相關資料,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.jsVue2.x-使用防抖以及節流的示例

    Vue2.x-使用防抖以及節流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節流的示例,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Kyara6372022-01-25
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 国产韩国精品一区二区三区 | 女教师高潮叫床视频在线观看 | 国产精品日韩一区二区 | 亚洲第一成人在线视频 | 日本韩国欧美一区 | 综合网视频 | 成人精品一区二区 | 97成人在线| 香蕉久久a毛片 | 久久精彩 | 色站综合 | 国产在线不卡 | 久久精品国产一区二区电影 | 91网页版| 久久一区二 | 亚洲精品一区二区三区在线观看 | 欧美在线一区二区三区 | 黑人精品| 成人午夜精品一区二区三区 | 91激情在线 | 久久aⅴ国产欧美74aaa | 国产精品高清在线观看 | 久久国产精品免费一区二区三区 | 久久综合九九 | 成人性做爰av片免费看 | 久久e久久| 久久蜜桃精品一区二区三区综合网 | 中文av电影| 亚洲国产免费av | 99精品一区二区 | 久久精品日韩 | 在线观看av国产一区二区 | 亚洲人成网站999久久久综合 | 91夜色| 高清一区二区在线观看 | 欧美1区2区3区 | 一片毛片| 97超碰青青草| 国产午夜精品美女视频明星a级 | 久久国产乱 | www.国产精品 |