鍍金池/ 問答/HTML/ 關(guān)于Virtual DOM 算法的疑惑

關(guān)于Virtual DOM 算法的疑惑

剛過年,最近忙著找一份實習(xí)的工作。電話面試了幾家大公司,他們都提到了Virtual DOM 的 diff 算法,一下子讓我慌得不行,網(wǎng)上找來找去,學(xué)來學(xué)去還是有很多地方不是很明白。希望大佬們指點小妹一番。
深度剖析:如何實現(xiàn)一個 Virtual DOM 算法

clipboard.png
這里構(gòu)建一個真正的DOM樹,插到文檔當(dāng)中?這句話的意思應(yīng)該是全部更新,而react和vue都是按需更新,那么react 和 vue是如何根據(jù)最新的狀態(tài)更新dom的?

回答
編輯回答
不將就
  1. 根據(jù) jsf 或者 js描述一個頁面結(jié)構(gòu),這個結(jié)構(gòu)會被用來構(gòu)造真正的 DOM 樹,然后掛載到 container
    節(jié)點(就平時的 <div id="app"/>) 上。
  2. 狀態(tài)樹,它是聯(lián)系虛擬 DOM 和 真實 DOM的橋梁,所謂的雙向綁定就是靠這個中間人。頁面載入時的初始狀態(tài)樹就是由所有構(gòu)造函數(shù) (React.Component 之類的東西,里邊的 this.state = {...},就是在描述初始狀態(tài)樹)匯總而來。
  3. 每當(dāng) UI 事件、網(wǎng)絡(luò)事件導(dǎo)致新的狀態(tài)產(chǎn)生,就會導(dǎo)致狀態(tài)樹進(jìn)行迭代。方式就是根據(jù)新的狀態(tài)構(gòu)造一棵新的狀態(tài)樹,并與舊的進(jìn)行比對,掃描出涉及到的虛擬 DOM(因為你通過構(gòu)造函數(shù)里、props等等方式告訴系統(tǒng)哪些狀態(tài)與哪些節(jié)點相關(guān)),這一步有的叫 臟標(biāo)記,就是 節(jié)點臟了,要更新了 的意思。
  4. 臟標(biāo)記完成后,根據(jù)這些 臟節(jié)點 對真實 DOM 對應(yīng)的節(jié)點(一開始通過 jsf 或繼承 Component 等方式登記了這個信息)進(jìn)行更新,有的是改變樣式、有的是增刪、有的是重用節(jié)點修改內(nèi)容、有的是修改節(jié)點值(value 等等)。

然后 2 3 步循環(huán)。

太久沒看 reactvue 了,不知道現(xiàn)在有沒有更新思路,記憶里是這樣的。

2018年1月31日 04:50
編輯回答
尛憇藌

react沒有深入學(xué)習(xí)。前段時間看過Vue的diff。

數(shù)據(jù)更新后setter方法會重新render出一個VNode,也就會有新的虛擬節(jié)點樹。新舊樹同層比較,修正更改的部分,再重新渲染到視圖上。

Vue采取了異步更新的策略,setter方法通知的watcher會經(jīng)過過濾進(jìn)入一個隊列,在nextTick時一次性執(zhí)行一批,由于watcher會被過濾,短時間內(nèi)頻繁的修改一個數(shù)據(jù),也不會重復(fù)執(zhí)行patch和diff的過程。

2017年7月15日 02:26
編輯回答
莫小染

在react/vue中:

state改變-->虛擬DOM更新-->虛擬DOM比較(diff算法)-->渲染變化部分
2017年9月4日 15:23
編輯回答
艷骨

簡單講一下我的理解:

先拋開框架本身,理解上述的幾個步驟。
1.用javascript對象結(jié)構(gòu)表示DOM樹的結(jié)構(gòu),然后用樹構(gòu)建一個真正的樹
2.當(dāng)狀態(tài)變更的時候,重新造一顆樹,然后用新舊樹對比
3.把2所記錄的差異應(yīng)用到步驟1所構(gòu)建的DOM樹上,視圖更新。

首先,簡單描述就是。所有節(jié)點,都是通過js來創(chuàng)建,這樣我們才有辦法用js來保存一個虛擬dom樹。

現(xiàn)在有了虛擬dom樹了,我們需要面對兩個問題。

  1. 虛擬dom 如何更新到界面上
  2. 后續(xù)如何來修改界面上的dom

第一點,通過虛擬dom,以一定的算法來生成一個真實的dom樹,然后以某種方式插入到界面中??赡苁沁@樣xxx.innerHtml = xxx...

第二點,也就是更新dom,但是頁面上的節(jié)點數(shù)非常的多,所以我們希望以最快的速度來更新dom。
那么毫無疑問,目前內(nèi)存中應(yīng)該是最為方便的,也最快的。

于是就出來了各式各樣的diff算法。

首先想想,你能實現(xiàn)的最簡單的方式。

遍歷最新的節(jié)點與之前生成樹進(jìn)行比較,比如你隨意修改了一個節(jié)點,找到兩顆樹之間修改的復(fù)雜度是o(n3).

這時候React出來了(我就了解react),我們要降低算法復(fù)雜度,我對我需要比較的節(jié)點來進(jìn)行限制。就是我認(rèn)為我們是同級的我才比較。

React 通過同級比較,將算法復(fù)雜度降低到o(n),

盜了張圖

clipboard.png
圖片來源

Matt-Esch 一個diff算法
snabbdo 另外一個

diff算法,怎么寫都是算法,重點的是不同的diff他們的思路如何實現(xiàn)的。

如何降低算法復(fù)雜度,也就是制定規(guī)則,或者預(yù)處理。

比如react就是通過只比較同層級直接的變化,那么我就可以從一棵樹的層級,直接定位到另一顆樹的對應(yīng)層級上,而不需要去遍歷整顆樹,也就是算法優(yōu)化問題。

菜鳥愚見。。

2017年8月29日 15:22