React將DOM抽象為虛擬DOM, 然后通過(guò)新舊虛擬DOM 這兩個(gè)對(duì)象的差異(Diff算法),最終只把變化的部分重新渲染,提高渲染效率的過(guò)程; (概念講完再描述一遍)
一句話: 用 JS 對(duì)象的形式,來(lái)表現(xiàn)一棵真是的 DOM 樹(shù);
Diff 算法
- 當(dāng)你實(shí)際開(kāi)發(fā)使用React的時(shí)候,在某個(gè)時(shí)間點(diǎn) render() 函數(shù)創(chuàng)建了一棵React元素樹(shù),也就模擬一個(gè)虛擬 DOM 樹(shù)号枕,
- 在下一個(gè)state或者props更新的時(shí)候储藐,render() 函數(shù)將創(chuàng)建一棵新的React元素樹(shù), 也就模擬了一個(gè)新的虛擬 DOM 樹(shù)再来,
- 既然模擬出了新舊兩棵DOM 樹(shù), 那么如何高效的進(jìn)行新舊兩棵樹(shù)的對(duì)比呢??
- 當(dāng)然是使用 DIff 算法...
-
傳統(tǒng)的 Diff 算法也是一直都有的;
- 但是它的時(shí)間復(fù)雜度為O(n^3)
意思是: 在React中更新10個(gè)元素則需要進(jìn)行1000次的比較鸽斟。(1000個(gè)===10億)
- 但是它的時(shí)間復(fù)雜度為O(n^3)
-
React 通過(guò)制定大膽的策略琢歇,將 O(n^3) 復(fù)雜度的問(wèn)題轉(zhuǎn)換成 O(n^1=n) 復(fù)雜度的問(wèn)題育韩。
- 兩個(gè)不同類型的元素會(huì)產(chǎn)生不同的樹(shù) <MyTest /> 和 <MyComponent />
- 對(duì)于同一層級(jí)的一組子節(jié)點(diǎn)擦酌,它們可以通過(guò)唯一 key 進(jìn)行區(qū)分
- 基于以上兩個(gè)前提策略宵晚,React 分別對(duì) tree diff、component diff 以及 element diff 三種 diff 方法是 進(jìn)行算法優(yōu)化维雇,
- 下面介紹優(yōu)化后的幾種算法
Tree Diff
概念: 將新舊兩顆虛擬 DOM 樹(shù),按照層級(jí)對(duì)應(yīng)的關(guān)系,從頭到尾的遍歷一遍,,就能找到那些元素是需要更新的,這種方式: Tree Diff
1 只會(huì)對(duì)相同顏色方框內(nèi)(同級(jí))的DOM節(jié)點(diǎn)進(jìn)行比較淤刃,即同一父節(jié)點(diǎn)下的所有子節(jié)點(diǎn)
2 當(dāng)發(fā)現(xiàn)節(jié)點(diǎn)已經(jīng)不存在,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除掉吱型,不會(huì)用于進(jìn)一步的比較
- 執(zhí)行過(guò)程:create A -> create B -> create C -> delete A
Component Diff
不同組件之間的對(duì)比
概念: 在對(duì)比每一個(gè)層級(jí)的時(shí)候,會(huì)有自己的組件,這種組件的對(duì)比方式就叫: Component Diff ;
? 這種對(duì)比方法其實(shí)比較的就是類型.↓↓↓
- 如果類型相同,暫時(shí)不更新,
- 如果類型不相同,就需要更新; ( 刪除舊的組件,再創(chuàng)建一個(gè)新的組件,插入到刪除組件的那個(gè)位置)
- 執(zhí)行過(guò)程:delete D -> create G
Element Diff
同一層級(jí)中元素之間的對(duì)比
概念: 在類型相同的組件內(nèi), 再繼續(xù)對(duì)比組件內(nèi)部的元素,查看內(nèi)部元素是否相同,如果需要修改,找到需要修改的元素,進(jìn)行針對(duì)性的修改! 這種方式就叫: Element Diff
三種節(jié)點(diǎn)操作:
1 INSERT_MARKUP(插入)
2 MOVE_EXISTING(移動(dòng))
3 REMOVE_NODE(刪除)
INSERT_MARKUP:新的 component 類型不在老集合里逸贾,需要對(duì)新節(jié)點(diǎn)執(zhí)行插入操作。
MOVE_EXISTING:老的集合包含新的 component 類型津滞,就需要做移動(dòng)操作铝侵,可以復(fù)用以前的 DOM 節(jié)點(diǎn)。
REMOVE_NODE:老的 component 不在新集合里的触徐,需要執(zhí)行刪除操作 或者 老的 component 類型在新集合里也有咪鲜,但對(duì)應(yīng)的 element 不同則不能直接復(fù)用和更新,需要執(zhí)行刪除操作
-
執(zhí)行過(guò)程:B != A锌介,則創(chuàng)建并插入 B嗜诀,刪除 A;以此類推孔祸,創(chuàng)建并插入 A、D发皿、C崔慧,刪除 B、C穴墅、D
Element Diff 02.png 執(zhí)行過(guò)程:B惶室、D 不做任何操作,A玄货、C 進(jìn)行移動(dòng)操作
diff 算法總結(jié):
保持完整的結(jié)構(gòu),有利于性能的提升
盡量使用相同類型的組件
在進(jìn)行 Element 或Component 級(jí)別對(duì)比的時(shí)候,為了提高對(duì)比的效率, React 推薦我們?yōu)槊總€(gè) for 循環(huán)創(chuàng)建出來(lái)的元素或者組件,提供一個(gè)唯一的 key;
Tree diff :將新舊兩棵 DOM 樹(shù),按照層級(jí)對(duì)應(yīng)的關(guān)系,這樣只需要對(duì)樹(shù)進(jìn)行一次遍歷,就能夠找到哪些元素是需要更新的;
Component Diff: 在對(duì)比每一層的時(shí)候,每一層都有自己的組件, 那么組件之間的對(duì)比,叫做 Component diff , 對(duì)比的方式,就是查看兩個(gè)組件的類型是否相同,如果相同,則暫時(shí)認(rèn)為不需要更新,如果類型不同,則表示更新(先把舊的組件刪除,再創(chuàng)建一個(gè)新的組件,插入到剛才刪除的位置);
Element Diff:如果新舊 DOM 樹(shù)中的組件類型相同,會(huì)繼續(xù)比較這兩個(gè)組件內(nèi)部的元素是否也相同,如果元素發(fā)生了改變,則找到需要修改的元素,有針對(duì)性的修改,這種組件內(nèi)部元素級(jí)別的對(duì)比叫: Element Diff;