在vue中對keep-alive的理解,它是如何實現的,具體緩存的是什么?

對keep-alive的理解,它是如何實現的,具體緩存的是什么?

  • (1)keep-alive有以下三個屬性:
    • 注意:keep-alive 包裹動態組件時,會緩存不活動的組件實例。
    • 主要流程
  • (2)keep-alive 的實現
    • render函數
  • (3)keep-alive 本身的創建過程和 patch 過程
  • (4)LRU (least recently used)緩存策略

如果需要在組件切換的時候,保存一些組件的狀態防止多次渲染,就可以使用 keep-alive 組件包裹需要保存的組件。

(1)keep-alive有以下三個屬性:

include 字符串或正則表達式,只有名稱匹配的組件會被匹配;
exclude 字符串或正則表達式,任何名稱匹配的組件都不會被緩存;
max 數字,最多可以緩存多少組件實例。

注意:keep-alive 包裹動態組件時,會緩存不活動的組件實例。

主要流程

判斷組件 name ,不在 include 或者在 exclude 中,直接返回 vnode,說明該組件不被緩存。
獲取組件實例 key ,如果有獲取實例的 key,否則重新生成。
key生成規則,cid +“∶∶”+ tag ,僅靠cid是不夠的,因為相同的構造函數可以注冊為不同的本地組件。
如果緩存對象內存在,則直接從緩存對象中獲取組件實例給 vnode ,不存在則添加到緩存對象中。 5.最大緩存數量,當緩存組件數量超過 max 值時,清除 keys 數組內第一個組件。

(2)keep-alive 的實現

const patternTypes: Array<Function> = [String, RegExp, Array] // 接收:字符串,正則,數組export default {name: 'keep-alive',abstract: true, // 抽象組件,是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在父組件鏈中。props: {include: patternTypes, // 匹配的組件,緩存exclude: patternTypes, // 不去匹配的組件,不緩存max: [String, Number], // 緩存組件的最大實例數量, 由于緩存的是組件實例(vnode),數量過多的時候,會占用過多的內存,可以用max指定上限},created() {// 用于初始化緩存虛擬DOM數組和vnode的keythis.cache = Object.create(null)this.keys = []},destroyed() {// 銷毀緩存cache的組件實例for (const key in this.cache) {pruneCacheEntry(this.cache, key, this.keys)}},mounted() {// prune 削減精簡[v.]// 去監控include和exclude的改變,根據最新的include和exclude的內容,來實時削減緩存的組件的內容this.$watch('include', (val) => {pruneCache(this, (name) => matches(val, name))})this.$watch('exclude', (val) => {pruneCache(this, (name) => !matches(val, name))})},
}

render函數

1.會在 keep-alive 組件內部去寫自己的內容,所以可以去獲取默認 slot 的內容,然后根據這個去獲取組件
2.keep-alive 只對第一個組件有效,所以獲取第一個子組件。
3.和 keep-alive 搭配使用的一般有:動態組件 和router-view

render () {//function getFirstComponentChild (children: ?Array<VNode>): ?VNode {if (Array.isArray(children)) {for (let i = 0; i < children.length; i++) {const c = children[i]if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {return c}}}}const slot = this.$slots.default // 獲取默認插槽const vnode: VNode = getFirstComponentChild(slot)// 獲取第一個子組件const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions // 組件參數if (componentOptions) { // 是否有組件參數// check patternconst name: ?string = getComponentName(componentOptions) // 獲取組件名const { include, exclude } = thisif (// not included(include && (!name || !matches(include, name))) ||// excluded(exclude && name && matches(exclude, name))) {// 如果不匹配當前組件的名字和include以及exclude// 那么直接返回組件的實例return vnode}const { cache, keys } = this// 獲取這個組件的keyconst 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.keyif (cache[key]) {// LRU緩存策略執行vnode.componentInstance = cache[key].componentInstance // 組件初次渲染的時候componentInstance為undefined// make current key freshestremove(keys, key)keys.push(key)// 根據LRU緩存策略執行,將key從原來的位置移除,然后將這個key值放到最后面} else {// 在緩存列表里面沒有的話,則加入,同時判斷當前加入之后,是否超過了max所設定的范圍,如果是,則去除// 使用時間間隔最長的一個cache[key] = vnodekeys.push(key)// prune oldest entryif (this.max && keys.length > parseInt(this.max)) {pruneCacheEntry(cache, keys[0], keys, this._vnode)}}// 將組件的keepAlive屬性設置為truevnode.data.keepAlive = true // 作用:判斷是否要執行組件的created、mounted生命周期函數}return vnode || (slot && slot[0])
}

keep-alive 具體是通過 cache 數組緩存所有組件的 vnode 實例。當 cache 內原有組件被使用時會將該組件 key 從 keys 數組中刪除,然后 push 到 keys數組最后,以便清除最不常用組件。
實現步驟:
1.獲取 keep-alive 下第一個子組件的實例對象,通過他去獲取這個組件的組件名
2.通過當前組件名去匹配原來 include 和 exclude,判斷當前組件是否需要緩存,不3.需要緩存,直接返回當前組件的實例vNode需要緩存,判斷他當前是否在緩存數組里面:
(1)存在,則將他原來位置上的 key 給移除,同時將這個組件的 key 放到數組最后面(LRU)
(2)不存在,將組件 key 放入數組,然后判斷當前 key數組是否超過 max 所設置的范圍,超過,那么削減未使用時間最長的一個組件的 key
4.最后將這個組件的 keepAlive 設置為 true

(3)keep-alive 本身的創建過程和 patch 過程

緩存渲染的時候,會根據 vnode.componentInstance(首次渲染 vnode.componentInstance 為 undefined) 和 keepAlive 屬性判斷不會執行組件的 created、mounted 等鉤子函數,而是對緩存的組件執行 patch 過程∶ 直接把緩存的 DOM 對象直接插入到目標元素中,完成了數據更新的情況下的渲染過程。
組件的首次渲染∶判斷組件的 abstract 屬性,才往父組件里面掛載 DOM

// core/instance/lifecycle
function initLifecycle (vm: Component) {const options = vm.$options// locate first non-abstract parentlet parent = options.parentif (parent && !options.abstract) { // 判斷組件的abstract屬性,才往父組件里面掛載DOMwhile (parent.$options.abstract && parent.$parent) {parent = parent.$parent}parent.$children.push(vm)}vm.$parent = parentvm.$root = parent ? parent.$root : vmvm.$children = []vm.$refs = {}vm._watcher = nullvm._inactive = nullvm._directInactive = falsevm._isMounted = falsevm._isDestroyed = falsevm._isBeingDestroyed = false
}

判斷當前 keepAlive 和 componentInstance 是否存在來判斷是否要執行組件 prepatch 還是執行創建 componentlnstance

// core/vdom/create-component
init (vnode: VNodeWithData, hydrating: boolean): ?boolean {if (vnode.componentInstance &&!vnode.componentInstance._isDestroyed &&vnode.data.keepAlive) { // componentInstance在初次是undefined!!!// kept-alive components, treat as a patchconst mountedNode: any = vnode // work around flowcomponentVNodeHooks.prepatch(mountedNode, mountedNode) // prepatch函數執行的是組件更新的過程} else {const child = vnode.componentInstance = createComponentInstanceForVnode(vnode,activeInstance)child.$mount(hydrating ? vnode.elm : undefined, hydrating)}},

prepatch 操作就不會在執行組件的 mounted 和 created 生命周期函數,而是直接將 DOM 插入

(4)LRU (least recently used)緩存策略

LRU 緩存策略∶ 從內存中找出最久未使用的數據并置換新的數據。
LRU(Least rencently used)算法根據數據的歷史訪問記錄來進行淘汰數據,其核心思想是 “如果數據最近被訪問過,那么將來被訪問的幾率也更高”。 最常見的實現是使用一個鏈表保存緩存數據,詳細算法實現如下∶

1.新數據插入到鏈表頭部
2.每當緩存命中(即緩存數據被訪問),則將數據移到鏈表頭部
3.鏈表滿的時候,將鏈表尾部的數據丟棄。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/717848.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717848.shtml
英文地址,請注明出處:http://en.pswp.cn/news/717848.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數字化轉型導師堅鵬:證券公司數字化營銷

證券公司數字化營銷 ——借力數字化技術實現零售業務的批量化、精準化、場景化、智能化營銷 課程背景&#xff1a; 很多證券公司存在以下問題&#xff1a; 不知道如何提升證券公司數字化營銷能力&#xff1f; 不知道證券公司如何開展數字化營銷工作&#xff1f; 不知道…

胎神游戲集第二期

延續上一期 一、海島奇胎 #include<bits/stdc.h> #include<windows.h> #include<stdio.h> #include<conio.h> #include<time.h> using namespace std; typedef BOOL (WINAPI *PROCSETCONSOLEFONT)(HANDLE, DWORD); PROCSETCONSOLEFONT SetCons…

Linux 安裝pip和換源

一 配置文檔 Linux和macOS&#xff1a; 全局配置&#xff1a;/etc/pip.conf 用戶級配置&#xff1a;~/.pip/pip.conf 或 ~/.config/pip/pip.conf 二 下載 和 安裝 # pip 安裝 wget https://bootstrap.pypa.io/get-pip.py python get-pip.py 三 查看和升級 pip -Vpython -m…

GO語言學習筆記(與Java的比較學習)(十一)

協程與通道 什么是協程 一個應用程序是運行在機器上的一個進程&#xff1b;進程是一個運行在自己內存地址空間里的獨立執行體。一個進程由一個或多個操作系統線程組成&#xff0c;這些線程其實是共享同一個內存地址空間的一起工作的執行體。 并行是一種通過使用多處理器以提…

Java虛擬機 - JVM

JVM的內存區域劃分 JVM它其實也是一個進程,進程運行的過程中,會從操作系統中申請一些資源.內存就是其中的一種.這些內存就支撐了java程序的運行.JVM從系統中申請的一大塊內存,會根據實際情況和使用用途來劃分出不同的空間,這個就是區域劃分.它一般分為 堆區, 棧區, 程序計數器…

springboot240基于Spring boot的名城小區物業管理系統

基于Spring boot的名城小區物業管理系統的設計與實現 摘要 當下&#xff0c;正處于信息化的時代&#xff0c;許多行業順應時代的變化&#xff0c;結合使用計算機技術向數字化、信息化建設邁進。以前相關行業對于物業信息的管理和控制&#xff0c;采用人工登記的方式保存相關數…

InnoDB存儲引擎對MVCC的實現

MVCC MVCC的目的 在搞清楚MVCC之前,我們要搞懂一個問題,MVCC到底解決的是什么問題? 我用一句話概括,那就是為了解決讀-寫可以一起的問題! 在我們的印象里,InnoDB可以讀讀并發,不能讀寫并發,或者寫寫并發 這是很正常的想法,因為如果讀寫并發的化,會有并發問題 而對于寫寫…

帶壓縮路徑的并查集

find帶壓縮路徑的并查集 int fa[]; void init(int _size) {for(int i0;i<_size;i){fa[i] i;} } int find(int aim) {int cur aim;while (fa[aim] ! aim){aim fa[aim];}while (fa[cur] ! cur){int tmp cur;cur fa[cur];fa[tmp] aim;}return aim; } void join(int a,in…

構建安全的REST API:OAuth2和JWT實踐

引言 大家好&#xff0c;我是小黑&#xff0c;小黑在這里跟咱們聊聊&#xff0c;為什么REST API這么重要&#xff0c;同時&#xff0c;為何OAuth2和JWT在構建安全的REST API中扮演著不可或缺的角色。 想象一下&#xff0c;咱們每天都在使用的社交媒體、在線購物、銀行服務等等…

file-upload-download

方式一 情況1&#xff1a; PostMapping("/download1")public ResponseEntity<byte[]> download1() throws Exception {// 下載文件目錄位置FileInputStream fis new FileInputStream("C:\\Users\\wsd\\Pictures\\susu.jpg");// 一次讀取bytes.leng…

Sqli-labs靶場第16關詳解[Sqli-labs-less-16]自動化注入-SQLmap工具注入

Sqli-labs-Less-16 #自動化注入-SQLmap工具注入 SQLmap用戶手冊&#xff1a;文檔介紹 - sqlmap 用戶手冊 以非交互式模式運行 --batch 當你需要以批處理模式運行 sqlmap&#xff0c;避免任何用戶干預 sqlmap 的運行&#xff0c;可以強制使用 --batch 這個開關。這樣&#xff0…

【視頻編碼\VVC】多樣化視頻編碼工具了解

除了通用編碼工具&#xff0c;VVC還針對特定特性的全景視頻、屏幕視頻開發了特定的編碼工具。 全景視頻編碼 360度全包圍視角的球面視頻。為了采用傳統的視頻編碼&#xff0c;全景視頻需要轉換為平面視頻&#xff0c;經緯度等角映射&#xff08;ERF&#xff09;、立方體映射&…

PostgreSQL操作筆記

基礎操作 數據庫相關 -- 查看所有數據庫 \l-- 切換到指定數據庫 \c 庫名-- 查看庫中所有表 \d執行SQL腳本 如果有現成的SQL腳本&#xff1a; \i 腳本路徑路徑一般需要用單引號引起來。 如果需要當場編輯一次性的SQL腳本&#xff0c;可以&#xff1a; \e執行上述命令后會進…

GC機制以及Golang的GC機制詳解

要了解Golang的GC機制,就需要了解什么事GC,以及GC有哪幾種實現方式 一.什么是GC 當一個電腦上的動態內存不再需要時&#xff0c;就應該予以釋放&#xff0c;以讓出內存&#xff0c;這種內存資源管理&#xff0c;稱為垃圾回收&#xff08;Garbage Collection&#xff09;&#x…

最長上升子序列(LIS)簡介及其例題分析

一.最長上升子序列&#xff08;LIS&#xff09;的相關知識 1.最長上升子序列&#xff08;Longest Increasing Subsequence&#xff09;&#xff0c;簡稱LIS&#xff0c;也有些情況求的是最長非降序子序列&#xff0c;二者區別就是序列中是否可以有相等的數。假設我們有一個序…

【論文筆記】Initializing Models with Larger Ones

Abstract 介紹權重選擇&#xff0c;一種通過從預訓練模型的較大模型中選擇權重子集來初始化較小模型的方法。這使得知識從預訓練的權重轉移到更小的模型。 它還可以與知識蒸餾一起使用。 權重選擇提供了一種在資源受限的環境中利用預訓練模型力量的新方法&#xff0c;希望能夠…

代碼隨想錄Day67 | 695.島嶼的最大面積 1020.飛地的數量

代碼隨想錄Day67 | 695.島嶼的最大面積 1020.飛地的數量 695.島嶼的最大面積1020.飛地的數量 695.島嶼的最大面積 文檔講解&#xff1a;代碼隨想錄 視頻講解&#xff1a; 狀態 采用bfs&#xff0c;這道題相較于之前的題變為了求島嶼的最大面積。那就說明我們每遇到一個新的島嶼…

【Linux】軟件管理yum | 編輯器vim | vim插件安裝

目錄 1. Linux軟件管理yum 1.1 什么是軟件包 1.2 查看軟件包 1.3 如何安裝軟件 1.4 如何卸載軟件 2. Linux編輯器vim 2.1 vim的基本概念 2.2 vim的基本操作 2.3 vim正常模式命令集 2.4 vim末行模式命令集 2.5 簡單vim配置 2.6 插件安裝 1. Vim-Plug 3. coc.nvim …

如何自己系統的學python

學習Python是一項很好的投資&#xff0c;因為它是一種既強大又易于學習的編程語言&#xff0c;適用于多種應用&#xff0c;如數據分析、人工智能、網站開發等。下面是一個系統學習Python的步驟建議&#xff1a; 基礎準備 安裝Python&#xff1a; 訪問Python官網下載最新版本的…

微服務獲取當前登錄用戶信息

一&#xff0c;實現思路 1&#xff0c;基于JWT令牌登陸方式 JWT實現登錄的&#xff0c;登錄信息就保存在請求頭的token中。因此要獲取當前登錄用戶&#xff0c;只要獲取請求頭&#xff0c;解析其中的token。 1&#xff09;&#xff0c;Gateway網關攔截&#xff0c;解析用戶信…