Virtual Dom的一些理解

1.1 virtualDom是什么

virtualDom是基于dom的基礎(chǔ)上抽象了一個由多個js對象組成的一個數(shù)據(jù)結(jié)構(gòu)(樹).

1.2 重繪與回流

回流:節(jié)點的大小與位置發(fā)生變化,會導(dǎo)致回流
重繪:是指將渲染樹的每個節(jié)點的信息轉(zhuǎn)換為屏幕上的像素的過程叫重繪
所以,回流必然導(dǎo)致重繪,(不涉及位置和大小的改變,如相同字?jǐn)?shù)的文字的改變只觸發(fā)重繪) 重繪不一定會觸發(fā)回流,兩者具備先后次序.

1.3 優(yōu)化

因為將渲染樹的信息繪制到屏幕上是一個較為耗時的操作,頻繁的操作dom而導(dǎo)致頻繁的觸發(fā)回流與重繪會大大影響性能.從而給用戶帶來不好的體驗.可以通過手動的方式來優(yōu)化:如樣式集中改變,使用fixed和absoulte等方法.

1.4 virtualDom對性能的優(yōu)化

如果沒有 Virtual DOM浅蚪,簡單來想就是直接重置 innerHTML,重繪渲染樹,在一個大型列表所有數(shù)據(jù)都變了的情況下,重繪渲染樹其實是一個還算合理的操作,相比于virtualDom來說,此時的效率更高,性能更好(虛擬dom多了一步j(luò)s計算diff的過程),但是在只有一些只有一行數(shù)據(jù)改變等情況下,重繪渲染樹就會顯得有大量的浪費.
為什么要有 Virtual DOM: 1)不管你的數(shù)據(jù)變化多少萌京,它保證了每次重繪的性能都可以接受瓮下;2) 你依然可以用類似重繪整個dom樹 的思路去寫你的應(yīng)用僻造。

1.5 為什么要用框架

框架的意義在于為你掩蓋底層的 DOM 操作,從而讓你的代碼更容易維護,沒有任何框架可以比純手動的優(yōu)化 DOM 操作更快慧耍,因為框架的 DOM 操作層需要應(yīng)對任何上層 API 可能產(chǎn)生的操作趋翻,它的實現(xiàn)必須是普適的,針對任何一個優(yōu)化點,我門都可以寫出比框架更快的手動優(yōu)化,但是在構(gòu)建一個實際應(yīng)用的時候,出于可維護性的考慮脖咐,我們不會為每一個地方都去做手動優(yōu)化师崎∧眨框架可以給你的保證是,你在不需要手動優(yōu)化的情況下犁罩,依然可以給你提供過得去的性能齐蔽。

2.代碼實現(xiàn)一個React - Virtual Dom

2.1 DOM元素分析

DOM是很慢的。如果我們把一個簡單的div元素的屬性都打印出來昼汗,你會看到:<img src="https://pic2.zhimg.com/50/d5cda33e28d83ba12368202645f9e35b_hd.jpg" data-rawwidth="1239" data-rawheight="336" class="origin_image zh-lightbox-thumb" width="1239" data-original="https://pic2.zhimg.com/d5cda33e28d83ba12368202645f9e35b_r.jpg"/>而這僅僅是第一層肴熏。真正的 DOM 元素非常龐大鬼雀,這是因為標(biāo)準(zhǔn)就是這么設(shè)計的顷窒。而且操作它們的時候你要小心翼翼,輕微的觸碰可能就會導(dǎo)致頁面重排,這可是殺死性能的罪魁禍?zhǔn)仔O鄬τ?DOM 對象鸦做,原生的 JavaScript 對象處理起來更快,而且更簡單谓着。DOM 樹上的結(jié)構(gòu)泼诱、屬性信息我們都可以很容易地用

JavaScript 對象表示出來:var element = {
 tagName: 'ul', // 節(jié)點標(biāo)簽名
 props: { // DOM的屬性,用一個對象存儲鍵值對
   id: 'list'
 },
 children: [ // 該節(jié)點的子節(jié)點
   {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寫法是:

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

</ul>既然原來 DOM 樹的信息都可以用 JavaScript 對象來表示赊锚,反過來治筒,你就可以根據(jù)這個用 JavaScript 對象表示的樹結(jié)構(gòu)來構(gòu)建一棵真正的DOM樹。

2.2 用JS對象模擬DOM樹

用 JavaScript 來表示一個 DOM 節(jié)點是很簡單的事情舷蒲,你只需要記錄它的節(jié)點類型耸袜、屬性,還有子節(jié)點:

element.jsfunction Element (tagName, props, children) {
 this.tagName = tagName
 this.props = props
 this.children = children
}

module.exports = function (tagName, props, children) {
 return new Element(tagName, props, children)
}

例如上面的 DOM 結(jié)構(gòu)就可以簡單的表示:var el = require('./element')

var ul = el('ul', {id: 'list'}, [
 el('li', {class: 'item'}, ['Item 1']),
 el('li', {class: 'item'}, ['Item 2']),
 el('li', {class: 'item'}, ['Item 3'])
])

現(xiàn)在ul只是一個 JavaScript 對象表示的 DOM 結(jié)構(gòu)牲平,頁面上并沒有這個結(jié)構(gòu)堤框。我們可以根據(jù)這個ul來構(gòu)建:

Element.prototype.render = function () {
 var el = document.createElement(this.tagName) // 根據(jù)tagName構(gòu)建
 var props = this.props

 for (var propName in props) { // 設(shè)置節(jié)點的DOM屬性
   var propValue = props[propName]
   el.setAttribute(propName, propValue)
 }

 var children = this.children || []

 children.forEach(function (child) {
   var childEl = (child instanceof Element)
     ? child.render() // 如果子節(jié)點也是虛擬DOM,遞歸構(gòu)建DOM節(jié)點
     : document.createTextNode(child) // 如果字符串纵柿,只構(gòu)建文本節(jié)點
   el.appendChild(childEl)
 })

 return el
}

render方法會根據(jù)tagName構(gòu)建一個真正的DOM節(jié)點蜈抓,然后設(shè)置這個節(jié)點的屬性,最后遞歸地把自己的子節(jié)點也構(gòu)建起來昂儒。所以只需要:

var ulRoot = ul.render()
document.body.appendChild(ulRoot)
上面的ulRoot是真正的DOM節(jié)點沟使,把它塞入文檔中,這樣body里面就有了真正的<ul>的DOM結(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>

代碼參考: https://github.com/tok-gogogo/virtual-dom

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荆忍,一起剝皮案震驚了整個濱河市格带,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刹枉,老刑警劉巖叽唱,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異微宝,居然都是意外死亡棺亭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門蟋软,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镶摘,“玉大人,你說我怎么就攤上這事岳守∑喔遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵湿痢,是天一觀的道長涝缝。 經(jīng)常有香客問我扑庞,道長,這世上最難降的妖魔是什么拒逮? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任罐氨,我火速辦了婚禮,結(jié)果婚禮上滩援,老公的妹妹穿的比我還像新娘栅隐。我一直安慰自己,他們只是感情好玩徊,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布租悄。 她就那樣靜靜地躺著,像睡著了一般恩袱。 火紅的嫁衣襯著肌膚如雪恰矩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天憎蛤,我揣著相機與錄音外傅,去河邊找鬼。 笑死俩檬,一個胖子當(dāng)著我的面吹牛萎胰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棚辽,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼技竟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屈藐?” 一聲冷哼從身側(cè)響起榔组,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎联逻,沒想到半個月后搓扯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡包归,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年锨推,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片公壤。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡换可,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出厦幅,到底是詐尸還是另有隱情沾鳄,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布确憨,位于F島的核電站译荞,受9級特大地震影響套媚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜磁椒,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玫芦。 院中可真熱鬧浆熔,春花似錦、人聲如沸桥帆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽老虫。三九已至叶骨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祈匙,已是汗流浹背忽刽。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夺欲,地道東北人跪帝。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像些阅,于是被迫代替她去往敵國和親伞剑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354