react初探(Virtual DOM分析)

Think

在 react 之前我只接觸過 mvvm 結(jié)構(gòu)的框架屑迂。

mvvm 采用這樣一種機(jī)制:只要在模版中聲明視圖組件是和什么狀態(tài)進(jìn)行綁定的蛉签,雙向綁定引擎就會在狀態(tài)更新的時候自動更新視圖装盯。

那對于更新視圖有沒有其他的實(shí)現(xiàn)呢县钥?

我們還可以考慮當(dāng)組件狀態(tài)發(fā)生變化時,就使用模版引擎去渲染整個視圖往声。用舊的視圖去替換掉新的視圖擂找。但是這樣做,就會出現(xiàn)大量的 DOM 操作烁挟。

而DOM操作是非秤ね荩可怕的??

var div = document.createElement("div");
var str = "";
for( var key in div ) {
  str = str + key + " ";
}
console.log(str);
DOM操作是很可怕的

因此,我們考慮到當(dāng)狀態(tài)變化時撼嗓,只更新發(fā)生變化的部分柬采,避免更新整顆 DOM 樹。

Virtual DOM

react 的核心概念便是 Virtual DOM且警。

相較于上面的原生 DOM 事件粉捻,使用原生 Javascript 來實(shí)現(xiàn)就更快,更簡單斑芜。

var element = {
  tagName: 'ul', // 節(jié)點(diǎn)標(biāo)簽名
  props: { // DOM的屬性肩刃,用一個對象存儲鍵值對
    id: 'list'
  },
  children: [ // 該節(jié)點(diǎn)的子節(jié)點(diǎn)
    {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
    {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
    {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
  ]
}

對應(yīng)的 HTML 結(jié)構(gòu)為:

<ul id='list'>
  <li class='item'>Item 1</li>
  <li class='item'>Item 2</li>
  <li class='item'>Item 3</li>
</ul>

既然 javascript 可以用來表示 dom ,那就可以通過 javascript 的樹結(jié)構(gòu)來構(gòu)成一顆 dom 樹杏头。

這樣盈包,在發(fā)生狀態(tài)變更時,我們可以通過對比舊的樹和新的樹醇王,來記錄差異呢燥。只針對差異部分進(jìn)行 dom 操作。這樣寓娩,頁面更新了叛氨,而 dom 操作也只變更了不同的地方。

Virtual DOM 本質(zhì)上就是在 JS 和 DOM 之間做了一個緩存棘伴∧海可以類比 CPU 和硬盤,既然硬盤這么慢焊夸,我們就在它們之間加個緩存:既然 DOM 這么慢仁连,我們就在它們 JS 和 DOM 之間加個緩存。CPU(JS)只操作內(nèi)存(Virtual DOM)阱穗,最后的時候再把變更寫入硬盤(DOM)怖糊。

算法實(shí)現(xiàn)

  1. 構(gòu)建虛擬DOM ( element )

    • 用 JavaScript 來表示一個 DOM 節(jié)點(diǎn)時帅容,只需要記錄它的節(jié)點(diǎn)類型、屬性伍伤,還有子節(jié)點(diǎn)。

    • render方法會根據(jù)tagName構(gòu)建一個真正的DOM節(jié)點(diǎn)遣钳,然后設(shè)置這個節(jié)點(diǎn)的屬性扰魂,最后遞歸地把自己的子節(jié)點(diǎn)也構(gòu)建起來。

      ?

  2. 找出新舊 DOM 樹的區(qū)別 ( diff )

    比較兩棵DOM樹的差異是 Virtual DOM 算法最核心的部分蕴茴。兩個樹的完全的 diff 算法是一個時間復(fù)雜度為 O(n^3) 的問題劝评。但是在前端當(dāng)中,你很少會跨越層級地移動DOM元素倦淀。所以 Virtual DOM 只會對同一個層級的元素進(jìn)行對比:

    及第一層的 div 只會與第一層的 div 對比蒋畜,第二層的 div 只會與第二層的 div 對比。這樣算法復(fù)雜度就可以降到 O(n)撞叽。

    • 深度優(yōu)先遍歷姻成,記錄差異

    • 差異類型

    • 列表對比算法

      ?

  3. 將差異運(yùn)用到真正的 DOM 樹上 ( patch )

    我們可以對 DOM 樹進(jìn)行深度優(yōu)先的遍歷,遍歷的時候從生成的patches對象中找出當(dāng)前遍歷的節(jié)點(diǎn)差異愿棋,然后進(jìn)行 DOM 操作科展。

// 1. 構(gòu)建虛擬DOM
var tree = el('div', {'id': 'container'}, [
    el('h1', {style: 'color: blue'}, ['simple virtal dom']),
    el('p', ['Hello, virtual-dom']),
    el('ul', [el('li')])
])

// 2. 通過虛擬DOM構(gòu)建真正的DOM
var root = tree.render()
document.body.appendChild(root)

// 3. 生成新的虛擬DOM
var newTree = el('div', {'id': 'container'}, [
    el('h1', {style: 'color: red'}, ['simple virtal dom']),
    el('p', ['Hello, virtual-dom']),
    el('ul', [el('li'), el('li')])
])

// 4. 比較兩棵虛擬DOM樹的不同
var patches = diff(tree, newTree)

// 5. 在真正的DOM元素上應(yīng)用變更
patch(root, patches)

Mark:

  1. 如何實(shí)現(xiàn)一個 Virtual DOM 算法https://github.com/livoras/blog/issues/13
  2. Virtual DOM dom&&diff 算法實(shí)現(xiàn)http://f2e.souche.com/blog/react-vitural-dom-diffsuan-fa-wei-dai-ma-shi-xian/
  3. 一個比較深刻的react.js源碼分析http://purplebamboo.github.io/2015/09/15/reactjs_source_analyze_part_one/
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市糠雨,隨后出現(xiàn)的幾起案子才睹,更是在濱河造成了極大的恐慌,老刑警劉巖甘邀,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琅攘,死亡現(xiàn)場離奇詭異,居然都是意外死亡松邪,警方通過查閱死者的電腦和手機(jī)坞琴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來测摔,“玉大人置济,你說我怎么就攤上這事》姘耍” “怎么了浙于?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挟纱。 經(jīng)常有香客問我羞酗,道長,這世上最難降的妖魔是什么紊服? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任檀轨,我火速辦了婚禮胸竞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘参萄。我一直安慰自己卫枝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布讹挎。 她就那樣靜靜地躺著校赤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筒溃。 梳的紋絲不亂的頭發(fā)上马篮,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音怜奖,去河邊找鬼浑测。 笑死,一個胖子當(dāng)著我的面吹牛歪玲,可吹牛的內(nèi)容都是我干的迁央。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼读慎,長吁一口氣:“原來是場噩夢啊……” “哼漱贱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起夭委,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤幅狮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后株灸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崇摄,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年慌烧,在試婚紗的時候發(fā)現(xiàn)自己被綠了逐抑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡屹蚊,死狀恐怖厕氨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情汹粤,我是刑警寧澤命斧,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站嘱兼,受9級特大地震影響国葬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一汇四、第九天 我趴在偏房一處隱蔽的房頂上張望接奈。 院中可真熱鬧,春花似錦通孽、人聲如沸序宦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挨厚。三九已至,卻和暖如春糠惫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钉疫。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工硼讽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牲阁。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓固阁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親城菊。 傳聞我的和親對象是個殘疾皇子备燃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容