Vue原始碼循序漸進系列5 diff演算法

2022-02-10 21:20:22 字數 3166 閱讀 2107

知乎上有一篇文章挺有意思,叫做網上都說操作真實 dom 慢,但測試結果卻比 react 更快,為什麼?,旨在抨擊虛擬dom沒有那麼牛b,開啟題主所附的鏈結進去操作了幾把,刨去不同瀏覽器、硬體等差異條件,發現並沒有那麼糟糕,總的來說react除了第一次比原生的慢,後面的幾乎在渲染效率上較原生dom、angular等操作更快,主要原因裡面的朋友還是做了討論:

1. react首次需要建立virtual dom,這一過程比較耗時;

2. 後期再更新時,react利用diff演算法進行差異性更新,而原生dom操作方式需要先刪除之前的dom節點元素,然後再依次新增節點。

還是比較贊同尤大的說法,react採用virtual dom產生的主要是簡化普通前端開發人員的工作量,資料驅動讓我們能夠更加專注於業務邏輯開發,在效能優化方面是相對具有普適性,比較不是所有前端都是能夠有完美效能優化的能力,並且花大量時間去做優化工作可能並不會取到很好的正面效果(當然也不是說不去關注前端的效能優化問題)。好吧,言歸正傳,接下來,針對對vue資料響應式更新的資料更新過程。

當vue元件可觀察的資料發生改變時,通過資料的setter中的通知到對應的觀察watcher發生動作,最終我們知道這些改變可能觸發元件的render watcher進行頁面的重新渲染,即執行了mountcomponent中的updatecomponent元件更新方法:

-> core/instance/lifecycle.js

// 執行更新元件

updatecomponent = () =>

_update()接收兩個引數,通過_render()返回的乙個vnode根節點,以及是否為伺服器端渲染標識,在方法內部,核心操作就是呼叫掛載在原型鏈上的__patch__方法進行打補丁式的更新渲染操作。

vnode全部屬性約20來個,相比於原生dom節點操作起來確實輕便不少,看一下關於virtual dom的虛擬節點vnode核心屬性的相關定義:

vnode , _renderproxy: proxy, _self: vue, …}

key: string | number | void; //

parent: vnode | void; // component placeholder node

diff演算法是vue實現補丁式頁面渲染的核心,相對於傳統的dom渲染,vue假設web ui跨級移動操作少可忽略不計,將diff對比過程定義為同級對比,時間複雜度由o(n^3)降為o(n),借用一張經典的對比圖:

diff示例

給乙個diff對比栗子:

原孩子vnode列表, oldch: [a, b, c, d]    

操作後:

新孩子vnode列表,newwch: [a, d, e, a]

原oldch對應的節點在真實dom樹種簡單表示為:

約定oldch中的起止下標: olds、olde,newch中的起止下標:news、newe,依照diff原理推演在虛擬本層虛擬孩子節點列表發生變化的過程:

首先,第1次對比:

oldch: [a, b, c, d]    olds: a    olde: d

newch: [b, d, e, a] news: b newe: a

olds和news對比(a-b),未能匹配,然後olds和newe對比(a-a),對比對比成功,即a在真實dom樹種被移動到最後,觸發頁面進行渲染:

第2次對比:

oldch: [b, c, d]    olds: b    olde: d

newch: [b, d, e] news: b newe: e

olds和news對比(b-b),比對成功,未發生改變,不發生渲染動作:

第3次對比:

oldch: [c, d]    olds: c    olde: d

newch: [d, e] news: d newe: e

olds和news對比(c-d),未匹配;然後olds和newe對比(c-e),未匹配;再用olde和news(d-d),匹配成功,觸發頁面進行渲染:

第4次對比:

oldch: [c]    olds: c    olde: c

newch: [e] news: e newe: e

olds和news對比(c-e),未匹配;然後olds和newe對比(c-e),未匹配;再用olde和news(c-e),匹配未成功;接著再用olde和newe對比(c-e),均為成功;最後在oldch列表中挨著去查詢(雖然只有乙個節點),發現確實沒找到,那就新建立乙個dom節點,然後插到dom樹上對應位置:

第5次對比:

oldch: [c]    olds: c    olde: c

newch: news: null newe: null

發現newch中基本遍歷完了,old中還有乙個虛擬節點c未處理,標明這個節點是期望應該被移除,那就在dom樹種去掉c對應的真實節點:

emsp;vue根據diff思想更新dom樹,以盡量達到最小化回流重繪,不過還是要知道,構造virtualdom不是免費的,需要付諸相應的構造時間和記憶體空間。

另外,歡迎去本人git 可相互學習和star。

Linux循序漸進 1

第一課 什麼是linux 簡單地說,linux是一套免費使用和自由傳播的類unix作業系統,它主要用於基於i ntel x86系列cpu的計算機上。這個系統是由全世界各地的成千上萬的程式設計師設計和實現 的。其目的是建立不受任何商品化軟體的版權制約的 全世界都能自由使用的unix相容 產品。linu...

循序漸進學程式設計

軟體開發者是乙個日新月異的領域 it 中的大師,今天的程式設計方式與明天的程式設計或許截然不同,技術在不斷地革新,新語言 新平台的如雨後春筍般出現 更好的解決方案的冒出,因此我們需要跟得上節奏,我們沒有選擇,唯有努力提高自己。下面的幾點建議或許能幫助你成為乙個優秀地開發者。你是否聽說過 kaizen...

軟體開發 循序漸進

隨便寫了這麼點,呵呵,應該是比較凌亂的,也不完全,希望大家不要見笑。1 學習應該從基礎打起,不要一開始就嘗試最高深的技術。2 每看一本書,不要說這章我以前學習過了,也掌握的很好,因此我可以跳過這一章看更重要的了。3 對於作業,遇到不會的盡量不要立刻向別人請教。如果實在解決不了的問題,可以先完成你會的...