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