【用友iUAP專(zhuān)家講堂】React設(shè)計(jì)虛擬DOM優(yōu)劣
React是Facebook于2013年5月推出的一個(gè)用來(lái)構(gòu)建用戶(hù)界面的開(kāi)源JavaScript框架。React一經(jīng)推出,便受到國(guó)外開(kāi)發(fā)者的追捧,國(guó)內(nèi)的流行始于2014年年中,雖然起步晚,但是發(fā)展迅速,目前其相關(guān)開(kāi)發(fā)教程和使用文檔已遍布國(guó)內(nèi)各大技術(shù)社區(qū)和論壇,其中不乏一些對(duì)比性質(zhì)的話(huà)題,例如:React.js和Angular.js的優(yōu)劣對(duì)比。
React的迅速成名的背后,與其對(duì)DOM(文檔對(duì)象模型,Document Object Model)操作的高性能特性是密不可分的。DOM的渲染效率,一直是前端交互開(kāi)發(fā)的重要性能瓶頸,目前主流JavaScript框架中的操作大量依賴(lài)于DOM提供的操作,從而導(dǎo)致了前端交互的效率低下,尤其是在大型復(fù)雜的頁(yè)面渲染中,這種情況表現(xiàn)的比較突出。而React另起爐灶,引入虛擬DOM模式的概念,巧妙繞開(kāi)了頻繁操作DOM的場(chǎng)景,并利用這種模式來(lái)處理DOM,從而讓其更新操作達(dá)到***的高效。
理解虛擬DOM的高性能,需要先了解一下DOM的渲染過(guò)程。
DOM渲染過(guò)程
所謂DOM渲染,即瀏覽器將HTML字符串轉(zhuǎn)換成網(wǎng)頁(yè)視圖并渲染視圖的過(guò)程。首先,瀏覽器的HTML解析器,會(huì)對(duì)HTML字符串進(jìn)行解析,并將它轉(zhuǎn)換成DOM樹(shù),同時(shí),CSS解析器也會(huì)解析HTML使用到的CSS樣式,生成一系列CSS規(guī)則;然后瀏覽器的渲染引擎將DOM樹(shù)和CSS規(guī)則進(jìn)行整合,并生成一個(gè)可用于視圖渲染的DOM渲染樹(shù);接著確定DOM布局,即每一個(gè)節(jié)點(diǎn)在瀏覽器中的確切位置;***一步是進(jìn)行繪制,將每一個(gè)節(jié)點(diǎn)的每一個(gè)像素繪制在屏幕上,于是我們便看到了期望的網(wǎng)頁(yè)視圖。深入了解這一過(guò)程中的復(fù)雜,我們可以再對(duì)HTML解析器的處理過(guò)程做一個(gè)特寫(xiě):HTML解析器中,有兩個(gè)程序在交替執(zhí)行: 分詞程序和解析程序;分詞程序負(fù)責(zé)將HTML字符串切分成合法的DOM標(biāo)簽字符串,然后交給解析程序處理,解析程序則將其添加到正在構(gòu)建的DOM樹(shù)中;當(dāng)分詞程序解析完所有的字符串后,DOM樹(shù)也便構(gòu)建完成了。
到這里,我們可以理解DOM的渲染為什么這么慢了: 這個(gè)過(guò)程,的確是太復(fù)雜了。在網(wǎng)頁(yè)交互中頻繁地對(duì)DOM進(jìn)行添加、移除操作,會(huì)極大地降低視圖渲染的效率,進(jìn)而降低交互的效率。而在React之前的UI更新操作(包括各大JavaScript框架的UI處理方式),都是先移除原始DOM,再進(jìn)行新DOM的構(gòu)建和插入,因而前端交互效率很低,交互體驗(yàn)很差。
React采用了虛擬DOM模式,于是這種情況改變了。
虛擬DOM,簡(jiǎn)單來(lái)說(shuō),是一個(gè)模擬DOM樹(shù)的JavaScript對(duì)象。React對(duì)UI的更新,并沒(méi)有使用傳統(tǒng)的方式: 移除指定區(qū)域的所有DOM節(jié)點(diǎn),然后把新節(jié)點(diǎn)添加進(jìn)去,而是采用了差異更新的辦法。React會(huì)在內(nèi)存中保留一份指定的原始DOM對(duì)應(yīng)的JavaScript對(duì)象,更新之前對(duì)比其和新DOM樹(shù)的JavaScript對(duì)象之間的差異,并精確計(jì)算出差異所在,然后對(duì)存在差異的DOM的屬性或文本進(jìn)行更新。例如,使用Ajax更新列表的內(nèi)容,由***頁(yè)轉(zhuǎn)向第二頁(yè)的過(guò)程中,如果兩頁(yè)數(shù)據(jù)形成的DOM樹(shù)有完全相同的結(jié)構(gòu),則不會(huì)有任何DOM的刪除或添加操作,React僅僅會(huì)更新存在差異的原始DOM的屬性或文本值。差異更新的辦法,將DOM的添加、刪除的操作頻次降到了***,也因而減輕了DOM渲染效率低的限制,從而讓React對(duì)UI的操作獲得了極大的速度提升。
到了這里,我們可以認(rèn)識(shí)到虛擬DOM的優(yōu)勢(shì)所在:差異對(duì)比、差異更新。但是對(duì)于這種思想,React的實(shí)現(xiàn)方式并不一定是***的,比如這種更新方式,需要對(duì)虛擬DOM對(duì)象進(jìn)行存儲(chǔ),那必然對(duì)內(nèi)存有額外的消耗。而且,如果瀏覽器采用了這種方式來(lái)更新DOM,這種思想便從源頭得到了實(shí)現(xiàn),各大JavaScript框架就無(wú)需再關(guān)心DOM操作的性能問(wèn)題,那React的高性能優(yōu)勢(shì)是不是就不存在,甚至?xí)兂梢环N累贅了?