導航:首頁 > 源碼編譯 > vue3diff演算法優化

vue3diff演算法優化

發布時間:2023-02-14 10:03:13

Ⅰ vue3 在哪些方便做了性能提升

概要
Vue (讀音 /vjuː/,類似於 view) 是一套用於構建用戶界面的漸進式框架。vue2版本階段已經證明了它的易用性和流行性,說明它已經足夠優秀在構建前端應用領域,而vue3的推出更是將性能提升做了最大的優化,更加易用、靈活、高效,未來是屬於vue3的時代,因此深入了解vue3相對vue2在哪些方面做了性能提升,怎麼提升性能的是非常有必要的。

編譯階優化段
在Vue2中,每個組件實例都對應一個 watcher 實例,它會在組件渲染的過程中把用到的數據property記錄為依賴,當依賴發生改變,觸發setter,則會通知watcher,從而使關聯的組件重新渲染

假如一個vue組件有如下模板結構:

可以看到,組件內部只有一個動態節點,剩餘一堆都是靜態節點,所以這里很多 diff 和遍歷其實都是不需要的,會造成性能浪費。因此,Vue3在編譯階段,做了進一步優化。主要有如下:

diff演算法優化

vue3在diff演算法中相比vue2增加了靜態標記關於這個靜態標記,其作用是為了會發生變化的地方添加一個flag標記,下次發生變化的時候直接找該地方進行比較,如下圖

靜態類型如下所示

靜態提升

Vue3中對不參與更新的元素,會做靜態提升,只會被創建一次,在渲染時直接復用這樣就免去了重復的創建節點,大型應用會受益於這個改動,免去了重復的創建操作,優化了運行時候的內存佔用

沒有做靜態提升之前

做了靜態提升之後

靜態內容_hoisted_1被放置在render 函數外,每次渲染的時候只要取 _hoisted_1 即可同時 _hoisted_1 被打上了 PatchFlag ,靜態標記值為 -1 ,特殊標志是負整數表示永遠不會用於 Diff

預字元串化

在平時vue開發過程中,組件當中沒有特別多的動態元素,大多都是靜態元素。比如:

在這個組件中,除了span元素是動態元素之外,其餘都是靜態節點,一般可以說是動靜比,動態內容 / 靜態內容,比例越小,靜態內容越多,比例越大,動態內容越多,vue3的編譯器它會非常智能地發現這一點,當編譯器遇到大量連續的靜態內容,會直接將它編譯為一個普通字元串節點,因為它知道這些內容永遠不會變化,都是靜態節點。

然而在vue2中,每個元素都會變成虛擬節點,一大堆的虛擬節點😱,這些全都是靜態節點,在vue3中它會智能地發現這一點。如下圖所示,我們可以很明顯的感受到vue3的巨大性能提升

緩存事件處理函數

比如存在如下事件處理函數
<button @click="count++">plus</button>

對比vue2和vue3的處理方式

在vue2中創建一個虛擬節點button,屬性裡面多了一個事件onclick,內容就是count++。在vue3中會認為這里的事件處理是不會變化的,不是說這次渲染是事件函數,下次就變成別的,於是vue3會智能地發現這一點,會做緩存處理,它首先會看一看緩存裡面有沒有這個事件函數,有的話直接返回,沒有的話就直接賦值為一個count++函數,保證事件處理函數只生成一次。

SSR優化

當靜態內容大到一定量級時候,會用createStaticVNode方法在客戶端去生成一個static node,這些靜態node,會被直接innerHtml,就不需要創建對象,然後根據對象渲染。

編譯前

編譯後

源碼體積有優化

與Vue2相比較,Vue3整體體積變小了,移除了一些比較冷門的feature:如 keyCode 支持作為 v-on 的修飾符、on、off 和 $once 實例方法、filter過濾、內聯模板等。tree-shaking 依賴 ES2015 模塊語法的靜態結構(即 import 和 export),通過編譯階段的靜態分析,找到沒有引入的模塊並打上標記。任何一個函數,如ref、reavtived、computed等,僅僅在用到的時候才打包,沒用到的模塊都被搖掉,打包的整體體積變小。

響應式實現優化

改用proxy api做數據劫持

響應式是惰性的

http://vue-next-template-explorer.netlify.app/

Ⅱ vue-diff演算法

渲染真實DOM的開銷是很大的,輕微的操作都可能導致頁面重新排版,非常耗性能。 相對於DOM對象,js對象處理起來更快,而且更簡單。 通過diff演算法對比新舊vdom之間的差異,可以批量的、最小化的執行 dom操作,從而提高性能。

常規:O(n^3) 遍歷樹1; 遍歷樹2; 排序; 1000個節點,十億的量級。

vue diff:O(n) 只比較同一層級 ;tag不相同,直接刪掉重建; 通過key來標識區分相同節點。

舊節點:A、B、C、D
新節點:A、E、B、C、D

1.1 兩個節點key是否相同(兩個key都沒有,即 undefined === undefined)

1.2 兩個節點tag標簽名是否一樣

1.3 兩個節點是否都為注釋節點

1.4 兩個節點的data isDef是否都相等(isDef:data !== undefined && data !== null)

1.5 兩個節點的input類型是否相同

1.6 節點a是否為非同步佔位

1.7 兩個節點的非同步函數是否相等

1.8節點b非同步函數的error是否為空(isUndef:data === undefined && data === null)

2.1 新舊節點都有子節點,調用updateChildren重排子節點

2.2 只有新節點有子節點,調用addVnodes添加子節點

2.3 只有舊節點有子節點,調用removeVnodes移除子節點

2.4 如果是文本節點,調用setTextContent更新節點文本內容

3.1.1 舊頭不存在,將舊頭游標往後移一位

3.1.2 舊尾不存在,將舊尾游標往前移一位

3.1.3 舊頭、新頭相同,更新節點,並將頭部游標往後移一位

3.1.4 舊尾、新尾相同,更新節點,並將尾部游標往前移一位

3.1.5 舊頭、新尾相同,更新節點,並且將舊頭移到尾部,舊頭游標往後移一位,新尾游標往前移一位

3.1.6 舊尾、新頭相同,更新節點,並且將舊尾移到頭部,新頭游標往後移一位,舊尾游標往前移一位

3.1.7 拿新頭遍歷舊子節點,找不到則新建一個節點;找到判斷節點是否相同,相同則更新節點,移動老節點,不同則新建一個節點

3.2.1 舊子節點先遍歷完畢,說明有新增節點,批量增加

3.2.2 新子節點先遍歷完畢,說明有節點刪除,批量移除

Ⅲ 原生快還是vue3快

vue3快。
_略雋巳鱟榧_ragment 支持多個根節點、Suspense 可以在組件渲染之前的等待時間顯示指定內容、Teleport 可以讓子組件能夠在視覺上跳出父組件(如父組件overflow:hidden)
_略鮒噶? v-memo,可以緩存 html 模板,比如 v-for 列表不會變化的就緩存,簡單說就是用內存換時間
_С? Tree-Shaking,會在打包時去除一些無用代碼,沒有用到的模塊,使得代碼打包體積更小
_略? Composition API 可以更好的邏輯復用和代碼組織,同一功能的代碼不至於像以前一樣太分散,雖然 Vue2 中可以用 minxin 來實現復用代碼,但也存在問題,比如方法或屬性名會沖突,代碼來源也不清楚等
_? Proxy 代替 Object.defineProperty 重構了響應式系統,可以監聽到數組下標變化,及對象新增屬性,因為監聽的不是對象屬性,而是對象本身,還可攔截 apply、has 等13種方法
_毓沽誦檳? DOM,在編譯時會將事件緩存、將 slot 編譯為 lazy 函數、保存靜態節點直接復用(靜態提升)、以及添加靜態標記、Diff 演算法使用 最長遞增子序列 優化了對比流程,使得虛擬 DOM 生成速度提升 200%
_С衷? 里使用 v-bind,給 CSS 綁定 JS 變數(color: v-bind(str))
_? setup 代替了 beforeCreate 和 created 這兩個生命周期
_略雋絲⒒肪車牧礁齬匙雍謐榧率? onRenderTracked 會跟蹤組件里所有變數和方法的變化、每次觸發渲染時 onRenderTriggered 會返回發生變化的新舊值,可以讓我們進行有針對性調試
_暇? Vue3 是用 TS 寫的,所以對 TS 的支持度更好

Ⅳ Vue2.x和Vue3.x渲染器的diff演算法

簡單來說,diff演算法有以下過程

正常Diff兩個樹的時間復雜度是 O(n^3) ,但實際情況下我們很少會進行 跨層級的移動DOM ,所以Vue將Diff進行了優化,從 O(n^3) -> O(n) ,只有當新舊children都為多個子節點時才需要用核心的Diff演算法進行同層級比較。

Vue2的核心Diff演算法採用了 雙端比較 的演算法,同時從新舊children的兩端開始進行比較,藉助key值找到可復用的節點,再進行相關操作。相比React的Diff演算法,同樣情況下可以減少移動節點次數,減少不必要的性能損耗,更加的優雅。

Vue3.x借鑒了 ivi 演算法和 inferno 演算法

在創建VNode時就確定其類型,以及在 mount/patch 的過程中採用 位運算 來判斷一個VNode的類型,在這個基礎之上再配合核心的Diff演算法,使得性能上較Vue2.x有了提升。(實際的實現可以結合Vue3.x源碼看。)

該演算法中還運用了 動態規劃 的思想求解最長遞歸子序列。

Ⅳ vue3載入性能

載入性能大大提升。
1、diff演算法加入了靜態標簽的概念,是vue3載入性能的一大優勢。
2、vue3內部使用了Tree-shaking技術,,沒有使用到的api,使vue3載入性能大大提升。
3、vue3打包時更好的支持tree-shaking,因此整體體積更小,載入更快

Ⅵ web前端diff 演算法深入一下

有同學問:能否詳細說一下 diff 演算法。

詳細的說,請閱讀這篇文章,有疑問的地方歡迎留言一起討論。

因為 diff 演算法是 vue2.x , vue3.x 以及 react 中關鍵核心點,理解 diff 演算法,更有助於理解各個框架本質。

說到「diff 演算法」,不得不說「虛擬 Dom」,因為這兩個息息相關。

比如:

等等

我們先來說說虛擬 Dom,就是通過 JS 模擬實現 DOM ,接下來難點就是如何判斷舊對象和新對象之間的差異。

Dom 是多叉樹結構,如果需要完整的對比兩棵樹的差異,那麼演算法的時間復雜度 O(n ^ 3),這個復雜度很難讓人接收,尤其在 n 很大的情況下,於是 React 團隊優化了演算法,實現了 O(n) 的復雜度來對比差異。

實現 O(n) 復雜度的關鍵就是只對比同層的節點,而不是跨層對比,這也是考慮到在實際業務中很少會去跨層的移動 DOM 元素。

虛擬 DOM 差異演算法的步驟分為 2 步:

實際 diff 演算法比較中,節點比較主要有 5 種規則的比較

部分源碼 https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L501 如下:

在 reconcileChildren 函數的入參中

diff 的兩個主體是:oldFiber(current.child)和 newChildren(nextChildren,新的 ReactElement),它們是兩個不一樣的數據結構。

部分源碼

很多時候手工優化 dom 確實會比 virtual dom 效率高,對於比較簡單的 dom 結構用手工優化沒有問題,但當頁面結構很龐大,結構很復雜時,手工優化會花去大量時間,而且可維護性也不高,不能保證每個人都有手工優化的能力。至此,virtual dom 的解決方案應運而生。

virtual dom 是「解決過多的操作 dom 影響性能」的一種解決方案。

virtual dom 很多時候都不是最優的操作,但它具有普適性,在效率、可維護性之間達到平衡。

virutal dom 的意義:

vue2.x 的 diff 位於 patch.js 文件中,該演算法來源於 snabbdom,復雜度為 O(n)。了解 diff 過程可以讓我們更高效的使用框架。react 的 diff 其實和 vue 的 diff 大同小異。

最大特點:比較只會在同層級進行, 不會跨層級比較。

對比之前和之後:可能期望將 直接移動到

的後邊,這是最優的操作。

但是實際的 diff 操作是:

vue 中也使用 diff 演算法,有必要了解一下 Vue 是如何工作的。通過這個問題,我們可以很好的掌握,diff 演算法在整個編譯過程中,哪個環節,做了哪些操作,然後使用 diff 演算法後輸出什麼?

解釋:

mount 函數主要是獲取 template,然後進入 compileToFunctions 函數。

compileToFunction 函數主要是將 template 編譯成 render 函數。首先讀取緩存,沒有緩存就調用 compile 方法拿到 render 函數的字元串形式,在通過 new Function 的方式生成 render 函數。

compile 函數將 template 編譯成 render 函數的字元串形式。後面我們主要講解 render

完成 render 方法生成後,會進入到 mount 進行 DOM 更新。該方法核心邏輯如下:

上面提到的 compile 就是將 template 編譯成 render 函數的字元串形式。核心代碼如下:

compile 這個函數主要有三個步驟組成:

分別輸出一個包含

parse 函數:主要功能是 將 template 字元串解析成 AST(抽象語法樹) 。前面定義的 ASTElement 的數據結構,parse 函數就是將 template 里的結構(指令,屬性,標簽) 轉換為 AST 形式存進 ASTElement 中,最後解析生成 AST。

optimize 函數(src/compiler/optomizer.js):主要功能是 標記靜態節點 。後面 patch 過程中對比新舊 VNode 樹形結構做優化。被標記為 static 的節點在後面的 diff 演算法中會被直接忽略,不做詳細比較。

generate 函數(src/compiler/codegen/index.js):主要功能 根據 AST 結構拼接生成 render 函數的字元串

其中 genElement 函數(src/compiler/codgen/index.js)是根據 AST 的屬性調用不同的方法生成字元串返回。

總之:

就是 compile 函數中三個核心步驟介紹,

patch 函數 就是新舊 VNode 對比的 diff 函數,主要是為了優化 dom,通過演算法使操作 dom 的行為降低到最低, diff 演算法來源於 snabbdom,是 VDOM 思想的核心。snabbdom 的演算法是為了 DOM 操作跨級增刪節點較少的這一目標進行優化, 它只會在同層級進行,不會跨層級比較。

總的來說:

在創建 VNode 就確定類型,以及在 mount/patch 的過程中採用位運算來判斷一個 VNode 的類型,在這個優化的基礎上再配合 Diff 演算法,性能得到提升。

可以看一下 vue3.x 的源碼:https://github.com/vuejs/vue/blob//src/core/vdom/patch.js

對 oldFiber 和新的 ReactElement 節點的比對,將會生成新的 fiber 節點,同時標記上 effectTag,這些 fiber 會被連到 workInProgress 樹中,作為新的 WIP 節點。樹的結構因此被一點點地確定,而新的 workInProgress 節點也基本定型。在 diff 過後,workInProgress 節點的 beginWork 節點就完成了,接下來會進入 completeWork 階段。

snabbdom 演算法:https://github.com/snabbdom/snabbdom

定位:一個專注於簡單性、模塊化、強大功能和性能的虛擬 DOM 庫。

snabbdom 中定義 Vnode 的類型(https://github.com/snabbdom/snabbdom/blob//src/vnode.ts#L12)

init 函數的地址:

https://github.com/snabbdom/snabbdom/blob//src/init.ts#L63

init() 函數接收一個模塊數組 moles 和可選的 domApi 對象作為參數,返回一個函數,即 patch() 函數。

domApi 對象的介麵包含了很多 DOM 操作的方法。

源碼:

https://github.com/snabbdom/snabbdom/blob//src/init.ts#L367

源碼:

https://github.com/snabbdom/snabbdom/blob//src/h.ts#L33

h() 函數接收多種參數,其中必須有一個 sel 參數,作用是將節點內容掛載到該容器中,並返回一個新 VNode。

在 vue2.x 不是完全 snabbdom 演算法,而是基於 vue 的場景進行了一些修改和優化,主要體現在判斷 key 和 diff 部分。

1、在 snabbdom 中 通過 key 和 sel 就判斷是否為同一節點,那麼在 vue 中,增加了一些判斷 在滿足 key 相等的同時會判斷,tag 名稱是否一致,是否為注釋節點,是否為非同步節點,或者為 input 時候類型是否相同等。

https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L35

2、diff 差異,patchVnode 是對比模版變化的函數,可能會用到 diff 也可能直接更新。

https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L404

Ⅶ Vue3基礎-模板語法

如果我們希望把數據顯示到模板(template)中,使用最多的語法是 「Mustache」語法 (雙大括弧) 的文本插值。

並且我們前端提到過,data返回的對象是有添加到Vue的響應式系統 中,當data中的數據發生改變時,對應的內容也會發生更新。

當然,Mustache中不僅僅可以是data中的屬性,也可以是一個JavaScript的表達式:

下面這種寫法是語句不是表達式,所以是錯誤的:

v-once用於指定元素或者組件只渲染一次,當數據發生變化時,元素或者組件以及其所有的子元素將視為靜態內容並且跳過,該指令可以用於性能優化。

如果添加到父節點,那麼所有的子節點也是只會渲染一次:

用於更新元素的 textContent,等價於"Mustache"語法,而且"Mustache"語法更靈活。

默認情況下,如果我們展示的內容本身是 html 的,那麼vue並不會對其進行特殊的解析。如果我們希望這個內容被Vue可以解析出來,那麼可以使用 v-html 來展示。

效果如下:

v-pre用於跳過元素和它的子元素的編譯過程,顯示原始的Mustache標簽。
跳過不需要編譯的節點,加快編譯的速度。

效果如下:

這個指令保持在元素上直到關聯組件實例結束編譯。

v-cloak 和 CSS 規則如 [v-cloak] { display: none } 一起用時,這個指令可以隱藏未編譯的 Mustache 標簽直到組件實例准備完畢,主要用於解決閃動問題,現在Vue3一般不會出現這個問題了。

<div> 不會顯示,直到編譯結束。

前面講的一系列指令,主要是將值插入到模板內容中。但是,除了內容需要動態來決定外,某些屬性我們也希望動態來綁定。比如動態綁定a元素的href屬性,動態綁定img元素的src屬性。

綁定屬性我們使用 v-bind: ,縮寫 : ,用於動態地綁定一個或多個 attribute,或一個組件 prop 到表達式。

v-bind用於綁定一個或多個屬性值,或者向另一個組件傳遞props值(這個學到組件時再介紹),在開發中,有哪些屬性需要動態進行綁定呢?還是有很多的,比如圖片的鏈接src、網站的鏈接href、動態綁定一些類、樣式等等。

v-bind有一個對應的語法糖,也就是簡寫方式,在開發中,我們通常會使用語法糖的形式,因為更簡潔。

注意 :Vue2 template模板中只能有一個根元素,Vue3 template模板中允許有多個根元素。

在開發中,有時候我們的元素class也是動態的,比如:當數據為某個狀態時,字體顯示紅色,當數據另一個狀態時,字體顯示黑色。

綁定class有兩種方式:對象語法,數組語法。

① 對象語法:我們可以傳給 :class (v-bind:class 的簡寫) 一個對象,以動態地切換 class。

② 數組語法:我們可以把一個數組傳給 :class,以應用一個 class 列表;

我們可以利用v-bind:style來綁定一些CSS內聯樣式,這是因為某些樣式我們需要根據數據動態來決定,比如某段文字的顏色,大小等等。

CSS屬性名可以用駝峰式 (camelCase) 或短橫線分隔 (kebab-case,記得用引號括起來) 來命名。

綁定style有兩種方式:對象語法,數組語法。

① 對象語法:

② 數組語法: :style 的數組語法可以將多個樣式對象應用到同一個元素上

在某些情況下,我們屬性的名稱可能也不是固定的。
前面我們無論綁定src、href、class、style,屬性名稱都是固定的,如果屬性名稱不是固定的,我們可以使用 :[屬性名]=「值」 的格式來定義,這種綁定的方式,我們稱之為動態綁定屬性。

如果我們希望將一個對象的所有屬性,綁定到元素上的所有屬性,應該怎麼做呢?非常簡單,我們可以直接使用 v-bind 綁定一個對象。

如下:info對象會被拆解成div的各個屬性。

前面我們綁定了元素的內容和屬性,在前端開發中另外一個非常重要的特性就是交互。
在前端開發中,我們需要經常和用戶進行各種各樣的交互,這個時候,我們就必須監聽用戶發生的事件,比如點擊、拖拽、鍵盤事件等等。

在Vue中如何監聽事件呢?使用v-on指令。接下來我們來看一下v-on的用法:

我們可以使用v-on來監聽一下點擊的事件:

v-on:click可以寫成@click,是它的語法糖寫法:

當然,我們也可以綁定其他的事件:

如果我們希望一個元素綁定多個事件,這個時候可以傳入一個對象:

當通過methods中定義方法,以供@click調用時,需要注意參數問題:

情況一:如果該方法不需要額外參數,那麼方法後的()可以不添加,並且方法的實現不用參數,直接就可以列印event。
情況二:如果需要同時傳入某個參數和event時,可以通過$event傳入事件,並且方法的實現必須按順序寫明參數。

@keyup.enter 代表enter鍵彈起的時候會調用onEnter方法,我們一般在方法裡面獲取輸入的值:

在某些情況下,我們需要根據當前的條件決定某些元素或組件是否渲染,這個時候我們就需要進行條件判斷了。

Vue提供了下面的指令來進行條件判斷:

下面我們來對它們進行學習。

v-if、v-else、v-else-if 用於根據條件來渲染某一塊的內容,這些內容只有在條件為true時,才會被渲染出來,這三個指令與JavaScript的條件語句 if、else、else if 類似。

v-if 的渲染原理:v-if是惰性的,當條件為false時,其判斷的內容完全不會被渲染或者會被銷毀掉,當條件為true時,才會真正渲染條件塊中的內容。

因為v-if是一個指令,所以必須將其添加到一個元素上,但是如果我們希望切換的是多個元素呢?
如果此時我們使用div包裹,div會被渲染到界面上來,但是我們並不希望div被渲染,這個時候,我們可以選擇使用template,template元素可以當做不可見的包裹元素,並且 v-if 可以添加到 template 上,但是最終template不會被渲染出來,類似於小程序中的block。

v-show和v-if的用法看起來是一致的,也是根據一個條件決定是否顯示元素或者組件。

首先,在用法上的區別:

其次,本質的區別:

開發中如何進行選擇呢?

在真實開發中,我們往往會從伺服器拿到一組數據,並且需要對其進行渲染。這個時候我們可以使用v-for來完成,v-for類似於JavaScript的for循環,可以用於遍歷一組數據。

v-for的基本格式是 "item in 數組" ,數組通常是來自data或者prop,也可以是其他方式,item是我們給每項元素起的一個別名,這個別名可以自定來定義。

我們知道,在遍歷一個數組的時候會經常需要拿到數組的索引,如果我們需要索引,可以使用格式 "(item, index) in 數組" ,注意順序,數組元素項item在前面,索引項index在後面。

類似於v-if,你可以使用 template 元素來循環渲染一段包含多個元素的內容。
我們使用template來對多個元素進行包裹,而不是使用div來完成,因為div會被渲染,template不會被渲染。而且如果有ul,ul裡面不推薦放div,只推薦放li。

Vue 將被偵聽的數組的變更方法進行了包裹,所以它們也將會觸發視圖更新,這些被包裹過的方法包括:

上面的方法會直接修改原來的數組,所以視圖會跟著更新。但是某些方法不會替換原來的數組,而是會生成新的數組,比如 filter()、concat() 和 slice(),這時候我們可以通過重新賦值的方式觸發視圖更新,如下:

在使用v-for進行列表渲染時,我們通常會給元素或者組件綁定一個key屬性。

這個key屬性有什麼作用呢?
我們先來看一下官方的解釋:key屬性主要用在Vue的虛擬DOM演算法,在新舊nodes對比時辨識VNodes。如果不使用key,Vue會使用一種最大限度減少動態元素並且盡可能的嘗試就地修改/復用相同類型元素的演算法,而使用key時,它會基於key的變化重新排列元素順序,並且會移除/銷毀key不存在的元素。

官方的解釋對於初學者來說並不好理解,比如下面的問題:
什麼是新舊nodes,什麼是VNode?
沒有key的時候,如何嘗試修改和復用的?
有key的時候,如何基於key重新排列的?

我們先來解釋一下VNode的概念:
VNode的全稱是Virtual Node,也就是虛擬節點。事實上,無論是組件還是元素,它們最終在Vue中表示出來的都是一個個VNode。VNode的本質是一個JavaScript的對象。

如果我們不只是一個簡單的div,而是有一大堆的元素,那麼它們應該會形成一個VNode Tree。

我們先來看一個案例:這個案例是當我們點擊按鈕時會在li中間插入一個f。

我們可以確定的是,這次更新對於ul和button是不需要進行更新,需要更新的是我們li的列表。在Vue中,對於相同父元素的子元素節點並不會重新渲染整個列表,因為對於列表中 a、b、c、d它們都是沒有變化的。在操作真實DOM的時候,我們只需要在中間插入一個f的li即可。

那麼Vue中對於列表的更新究竟是如何操作的呢?
Vue事實上會對於有key和沒有key會調用兩個不同的方法,有key,那麼就調用 patchKeyedChildren方法,沒有key,那麼就調用 patchUnkeyedChildren方法。

沒有key的diff演算法:

我們會發現上面的diff演算法效率並不高,c和d來說它們事實上並不需要有任何的改動,但是因為我們的c被f所使用了,所有後續所有的內容都要一次進行改動,並且最後進行新增。

有key的diff演算法:

所以我們可以發現,Vue在進行diff演算法的時候,會盡量利用我們的key來進行優化操作,在沒有key的時候我們的效率是非常低效的,在進行插入或者重置順序的時候,保持相同的key可以讓diff演算法更加的高效。

Ⅷ 面試中的網紅Vue源碼解析之虛擬DOM,你知多少呢深入解讀diff演算法

眾所周知,在前端的面試中,面試官非常愛考dom和diff演算法。比如,可能會出現在以下場景

滴滴滴,面試官發來一個面試邀請。接受邀請📞

我們都知道, key 的作用在前端的面試是一道很普遍的題目,但是呢,很多時候我們都只浮於知識的表面,而沒有去深挖其原理所在,這個時候我們的競爭力就在這被拉下了。所以呢,深入學習原理對於提升自身的核心競爭力是一個必不可少的過程。

在接下來的這篇文章中,我們將講解面試中很愛考的虛擬DOM以及其背後的diff演算法。 請認真閱讀本文~文末有學習資源免費共享!!!

虛擬DOM是用JavaScript對象描述DOM的層次結構。DOM中的一切屬性都在虛擬DOM中有對應的屬性。本質上是JS 和 DOM 之間的一個映射緩存。

要點:虛擬 DOM 是 JS 對象;虛擬 DOM 是對真實 DOM 的描述。

diff發生在虛擬DOM上。diff演算法是在新虛擬DOM和老虛擬DOM進行diff(精細化比對),實現最小量更新,最後反映到真正的DOM上。

我們前面知道diff演算法發生在虛擬DOM上,而虛擬DOM是如何實現的呢?實際上虛擬DOM是有一個個虛擬節點組成。

h函數用來產生虛擬節點(vnode)。虛擬節點有如下的屬性:
1)sel: 標簽類型,例如 p、div;
2)data: 標簽上的數據,例如 style、class、data-*;
3)children :子節點;
4) text: 文本內容;
5)elm:虛擬節點綁定的真實 DOM 節點;

通過h函數的嵌套,從而得到虛擬DOM樹。

我們編寫了一個低配版的h函數,必須傳入3個參數,重載較弱。

形態1:h('div', {}, '文字')
形態2:h('div', {}, [])
形態3:h('div', {}, h())

首先定義vnode節點,實際上就是把傳入的參數合成對象返回。

[圖片上傳失敗...(image-7a9966-1624019394657)]
然後編寫h函數,根據第三個參數的不同進行不同的響應。

當我們進行比較的過程中,我們採用的4種命中查找策略:
1)新前與舊前:命中則指針同時往後移動。
2)新後與舊後:命中則指針同時往前移動。
3)新後與舊前:命中則涉及節點移動,那麼新後指向的節點,移到 舊後之後
4)新前與舊後:命中則涉及節點移動,那麼新前指向的節點,移到 舊前之前

命中上述4種一種就不在命中判斷了,如果沒有命中,就需要循環來尋找,移動到舊前之前。直到while(新前<=新後&&舊前<=就後)不成立則完成。

如果是新節點先循環完畢,如果老節點中還有剩餘節點(舊前和舊後指針中間的節點),說明他們是要被刪除的節點。

如果是舊節點先循環完畢,說明新節點中有要插入的節點。

1.什麼是Virtual DOM 和Snabbdom
2.手寫底層源碼h函數
3.感受Vue核心演算法之diff演算法
4.snabbdom之核心h函數的工作原理

1、零基礎入門或者有一定基礎的同學、大中院校學生
2、在職從事相關工作1-2年以及打算轉行前端的朋友
3、對前端開發有興趣人群

Ⅸ vue3優化不包括

vue3優化不包括支持IE11。根據查詢相關公開資料信息顯示,Vue3做出的優化有diff演算法優化、靜態提升、事件監聽緩存、SSR優化。目的是讓代碼更易於開發和維護。vue3不再支持IE11,Vue在2.X版本支持IE11。

Ⅹ 你怎麼理解vue中的diff演算法

diff演算法是虛擬 DOM 的必然產物,通過新舊虛擬 DOM 對比,將變化的地方更新在真實 DOM 上,另外也需要 diff 高效的執行對比過程,從而降低時間復雜度
vue2中為了降低 watcher 力度,每個組件只有一個 watcher 與之對應,只有引入 diff 才能精確的找到發生變化的地方
diff 之所以發生變化,是引入組件數據的變化調用了 set 方法,導致 watcher能夠監控到數據的變化,導致其觸發 updateComponent 中 pathVnode方法,在 pathVnode 函數中對對比上一次渲染結果和新渲染結果.兩個節比較的過程就是發生diff的過程.整個更新過程叫做 path 過程,也叫打補丁的過程
diff 過程整體遵從深度優先,同層比較的策略;兩個節點之間比較會根據它們是否擁有子節點或者文本節點做不同的操作.比較兩組節點是演算法的重點.首先假設頭尾節點相同做 4 次比較嘗試,如果這 4 中方式都沒有找到,就按照通用方式遍歷查找.查找結束在按照情況處理剩下的節點;藉助 key,通常可以精確的找到相同的節點,因此整個 path 過程是非常高效的

閱讀全文

與vue3diff演算法優化相關的資料

熱點內容
c編譯器使用說明 瀏覽:703
鄭州前端程序員私活有風險嗎 瀏覽:10
小型螺桿機壓縮機 瀏覽:516
成人解壓最好的方法 瀏覽:48
最小製冷壓縮機 瀏覽:488
xampp支持python 瀏覽:367
深圳周立功單片機 瀏覽:58
圓上點與點之間角度演算法 瀏覽:867
怎麼知道微信關聯了哪些app 瀏覽:700
android事件驅動 瀏覽:886
簽約大屏系統源碼 瀏覽:806
安卓系統怎麼轉入平板 瀏覽:425
安卓手機相機怎麼提取文字 瀏覽:219
如何查看伺服器映射的外網地址 瀏覽:985
圖片刺綉演算法 瀏覽:675
阿里雲伺服器沒有實例 瀏覽:605
綿陽有沒有什麼app 瀏覽:849
怎麼用游俠映射伺服器 瀏覽:921
為什麼無意下載的app無法刪除 瀏覽:308
word2007打開pdf 瀏覽:118