倪新勇
(南京郵電大學,江蘇 南京 210000)
常規(guī)而言,想要針對應用進行優(yōu)化,一般會考慮到從硬件和軟件兩個方面實現(xiàn)提升。如果是針對硬件,常規(guī)的優(yōu)化方案主要包括擴大帶寬、服務集群等部署后端應用方式,而這些性能的提升都是依靠大量的硬件資金投入,購入相應的硬件設備以此提升處理數(shù)據(jù)的性能。而如果是針對軟件進行優(yōu)化,基本是軟件編碼流程優(yōu)化或者算法提升軟件的處理性能,此相對比之下,從軟件的方向進行技術優(yōu)化實現(xiàn)應用的性能提升更加具有實際意義。本文選定應用軟件編碼中的前端方向,通過虛擬DOM 技術,研究針對應用中的Web 界面的前端優(yōu)化。
若要針對前端性能進行優(yōu)化,首先要了解整個應用頁面的渲染流程。而想要了解頁面的渲染過程,瀏覽器渲染性能是必須要掌握的核心內容。瀏覽器是通過解析器負責對語法的解析,依據(jù)解析后的內容渲染整個網(wǎng)頁。
瀏覽器進行渲染的前提條件是瀏覽器在與用戶的功能交互過程中產(chǎn)生了網(wǎng)絡請求,之后向服務器端發(fā)送數(shù)據(jù)和請求對應需要的資源,完成此步驟后,需要完成的就是把從服務器中請求的資源渲染到頁面中對應的位置處。
瀏覽器把服務器端請求到的數(shù)據(jù)渲染成為應用頁面的整個過程是十分迅速的,其流程如下。
第一步,借助HTML 解析器,對數(shù)據(jù)中的HTML 元素節(jié)點解析之后以此構建出DOM 樹。
第二步,借助CSS 解析器,對數(shù)據(jù)中CSS 樣式文件包含的元素樣式和元素內連樣式進行解析并構建CSSOM 樹,也就是應用頁面的元素樣式表。
第三步,將DOM 樹和CSSOM 樹放在一起,根據(jù)節(jié)點結合構建渲染樹。其中的每個DOM 節(jié)點都含有掛載方法,對應各自節(jié)點的樣式信息。
第四步,渲染樹構建完,根據(jù)渲染樹中記錄的信息,瀏覽器開始調用layout(布局),為渲染樹上的每一個節(jié)點確定其在顯示頁面中出現(xiàn)的坐標位置。
第五步,在渲染樹上的節(jié)點的顯示坐標全部確定之后,接下來瀏覽器就會就調用每個節(jié)點paint(繪制)方法,將它們按照之前完成的樣式表和坐標位置一一對應后繪制出來顯示在頁面上。頁面渲染流程如圖1 所示。
圖1 頁面渲染流程圖
瀏覽器構建DOM 樹并渲染頁面的整個流程是一個循環(huán)漸進過程,并不是線性接力過程,這些過程在瀏覽器的流程不是完全獨立的,而是會有某個過程和時間點的交叉。
除了上述的瀏覽器頁面渲染流程之外,還有兩個經(jīng)常會觸發(fā)且會對瀏覽器的渲染性能產(chǎn)生影響的操作:
(1)回流。當頁面上某些元素節(jié)點位置信息發(fā)生變化時,瀏覽器會因為這些改動而重新從最底層開始計算該節(jié)點的位置,驗證并計算渲染樹。
(2)重繪。當頁面上某些元素節(jié)點樣式信息發(fā)生變化時(這些元素變化時不影響整個頁面的位置信息布局),瀏覽器會因為這些改動重新記錄節(jié)點的元素樣式,并更新渲染樹,進行重畫操作。
這兩個操作都是在原本的頁面內容渲染好之后又發(fā)生了資源的變動時,觸發(fā)的瀏覽器渲染機制對頁面的部分內容重新渲染,他們之間的區(qū)別主要是在于對頁面的整體布局是否產(chǎn)生影響。在實際應用的頁面中,這兩種操作都會對頁面的渲染性能產(chǎn)生影響,降低頁面加載速率,但是這兩種機制的出現(xiàn)在頁面的正常使用過程中是不可避免的,是屬于功能交互所帶來的額外耗費。但是如果在一個頁面功能多且繁雜的應用中,頻繁地觸發(fā)回流和重繪,則會給瀏覽器的渲染引擎帶來工作量和性能耗費。
當頁面頻繁地刷新或者出現(xiàn)用戶頁面交互產(chǎn)生的回流和重繪時,會出現(xiàn)很多需要處理和渲染的數(shù)據(jù)致使瀏覽器產(chǎn)生大量的DOM 操作,而一段時間過多的DOM操作需要瀏覽器頻繁的執(zhí)行渲染流程,這不僅會占用瀏覽器很大的硬件性能,甚至會影響到重新渲染顯示頁面速度,從而對應用的響應速度產(chǎn)生不好的影響,尤其是多次變動導致的頁面重新渲染帶來的耗費。
依據(jù)瀏覽器渲染流程,以及元素變動時帶來的額外渲染流程對性能耗費問題,只要能夠減少頁面中DOM操作的頻率,就可以實現(xiàn)對應用性能的優(yōu)化。而減少DOM 操作的頻率,就要在一定時間內,把這些DOM 操作一起掛載到頁面中??梢岳肑avaScript 模擬出一整個應用頁面中所有元素節(jié)點,從而構造出一棵依據(jù)DOM 樹中節(jié)點信息模仿而來的虛擬DOM 樹。而頁面中多次改動的變動信息由JavaScript 記錄之后,再讓瀏覽器根據(jù)這些節(jié)點的變動信息而對頁面進行一次性渲染。由JavaScript 模擬構建虛擬DOM 樹,根據(jù)頁面的變動,得出頁面變動前后的差異,再渲染出頁面,這就是虛擬DOM 技術。
假設應用頁面中的變動中是五十個節(jié)點發(fā)生位置信息的變動,按照之前介紹的常規(guī)的瀏覽器渲染流程,每存在一次DOM 操作,瀏覽器都將對整個頁面進行一遍繪制,總共要進行五十次的頁面繪制,這對瀏覽器的性能耗費是十分巨大的。而采用虛擬DOM 技術,并不會短時間內立即執(zhí)行那么多次的DOM 操作,而是將某段時間內五十次更新操作中的變動信息保存到本地JavaScript 對象中,之后依據(jù)這個JavaScript 對象將五十次更新信息一次性掛載到DOM 樹上,瀏覽器額外繪制一次頁面就完成了如此多的內容更新。
使用虛擬DOM 技術相比于直接進行DOM 操作具有很多優(yōu)勢,包括:虛擬DOM 技術使用JavaScript 為主,而不需要額外其他生產(chǎn)環(huán)境作為編譯支撐,且因為JavaScript 編寫的,有跨平臺能力;由于JavaScript 的執(zhí)行速度相對較快,虛擬DOM 通過多次操作JavaScript 記錄頁面變動減少了直接操作DOM 的次數(shù),所以虛擬DOM顯著地提高了頁面渲染效率。
一個應用頁面一般由很多個元素節(jié)點組合嵌套構成基本骨架,某一個元素節(jié)點的改變可能會導致附近有所聯(lián)系的節(jié)點也會產(chǎn)生連鎖變化。應用頁面包含的內容信息量越大,這種關聯(lián)變化就會產(chǎn)生越大的影響。如果頻繁地進行DOM 操作修改頁面布局,會使應用頁面出現(xiàn)明顯的卡頓,而使用虛擬DOM 可以直接減少修改頁面產(chǎn)生的DOM 操作的次數(shù),提升流暢度。
虛擬DOM 樹是根據(jù)真實DOM 樹模仿出來的,它們兩個是節(jié)點一一對應的同種樹狀數(shù)據(jù)結構,同時每個節(jié)點也都會包含相應全部屬性,而這些節(jié)點的屬性,不管在真正DOM 樹中的節(jié)點屬性還是在虛擬DOM 樹中的節(jié)點屬性都是一樣的,這是使用JavaScript 是對DOM 樹的一種抽象模仿表示。頁面中更新產(chǎn)生的所有的DOM 操作都會提前在虛擬DOM 上執(zhí)行,這樣會產(chǎn)生對應新的頁面的DOM 結構的新虛擬DOM 樹。新舊兩棵虛擬DOM 樹進行對比,得出差異點,之后瀏覽器根據(jù)這個差異點定位到實際需要更新的節(jié)點,在頁面中進行局部渲染。
步驟一:在最先首次頁面加載顯示時,根據(jù)真實DOM 結構,使用JavaScript 模擬其結構并構建出對應的虛擬DOM 樹,之后根據(jù)DOM 樹渲染成應用展示頁面。
步驟二:變動產(chǎn)生后,根據(jù)新的改動后的結構使用JavaScript 模擬出新虛擬DOM 樹,并且和步驟一中形成的舊的虛擬DOM 樹進行比較,新舊虛擬DOM 樹的區(qū)別就是需要計算出并且記錄的差異對象。
步驟三:記錄步驟二中所記錄的差異對象,之后應用到步驟一中的真正DOM 樹上,讓瀏覽器進行頁面的重新渲染以此實現(xiàn)頁面的內容更新。
2.2.1 模擬虛擬DOM 樹
要對以上的三個步驟進行實現(xiàn),完成實現(xiàn)虛擬DOM技術的應用,首先要用JavaScript 模擬表示頁面中DOM結構。借助JavaScript 對象,涵蓋節(jié)點中應該有的屬性就可以很方便地表示DOM 節(jié)點。通過JavaScript 對象的屬性表達記錄這些節(jié)點信息。這個過程中構建真正DOM樹,并且也構建出了虛擬DOM 樹,這棵虛擬DOM 樹與真正的DOM 樹包含的信息都是一樣的。
2.2.2 對比新舊虛擬DOM 樹
當頁面中的數(shù)據(jù)發(fā)生改動,產(chǎn)生了改變頁面結構的變動時,先通過JavaScript 模擬出最新頁面的虛擬DOM樹,然后新舊虛擬DOM 進行對比,得到頁面中變動節(jié)點的信息。
在正常頁面中的真實DOM 樹結構會很復雜,而根據(jù)其模仿出來的虛擬DOM 樹也會包含大量的節(jié)點,想要快速對比新舊兩棵虛擬DOM 樹,并得出它們之間的不同,需要有一個能實現(xiàn)快速對比的DIFF 算法。想要實現(xiàn)真正高效的虛擬DOM 樹需要重點對比兩個問題,比較兩棵DOM 樹的方法和記錄節(jié)點之間差異的方法。
通常來說,真正完整地比較新舊兩棵虛擬DOM 樹是具有相當大的計算量的,根據(jù)前端頁面中的通常操作來講,頁面中數(shù)據(jù)的更新很少會是跨級別的修改DOM節(jié)點。所以,在此優(yōu)化過程中只需考慮同級別的節(jié)點互相比較。
2.2.3 差異對象的應用
根據(jù)之前得到的差異對象,同時結合舊的虛擬DOM樹,得到在真實DOM 樹中需要修改的節(jié)點,進行真正的DOM 操作,對應修改真實的DOM 結構。
上文陳述了虛擬DOM 帶來的好處以及理論上對應用頁面的性能提升。為了驗證虛擬DOM 是否真的帶來了性能的提升,設計實驗驗證對比直接操作DOM 和使用虛擬DOM 技術渲染頁面的不同性能。根據(jù)常規(guī)應用操作考慮,設置實驗的步驟,對數(shù)據(jù)進行常規(guī)操作增加節(jié)點測試兩種不同的方案會對頁面渲染性能帶來什么樣不同的影響,得到直接操作DOM 和使用虛擬DOM 技術對頁面節(jié)點更新的性能對比。實驗的具體流程為,首先創(chuàng)建框架ul節(jié)點,之后使用ul 節(jié)點,在其內初始化li 節(jié)點之后,進行增加節(jié)點的操作,并增加對不同數(shù)量的節(jié)點變化響應時間的記錄,結果如圖2 所示。
圖2 虛擬DOM 和直接操作DOM 性能消耗對比圖
由圖2 數(shù)據(jù)可知,隨著需要操作節(jié)點數(shù)量的不斷增加,使用虛擬DOM 技術實現(xiàn)應用中節(jié)點更新的速度更高。
一個成熟的應用首先要確保頁面的流暢度和實現(xiàn)交互功能的響應速度,使用虛擬DOM 技術優(yōu)化頁面的渲染速度。根據(jù)虛擬DOM 技術以及其他的工程化的編碼思路,在此基礎上構建一個可視化構建商城頁面應用,可用于用戶快速生成H5 頁面。商城頁面構建應用中包含有很多對節(jié)點進行改動的操作,同時為了構建商城頁面的各個顯示部分和功能需求,還會存在很多的節(jié)點變動,是可以發(fā)揮出虛擬DOM 優(yōu)勢的理想應用。
為了完成可視化構建商城頁面的應用,最重點核心的功能是把商城頁面功能模塊搭建并組合起來,應用主要分為構成組件列表,效果預覽畫布,具體組件屬性控制調整列表三大模塊,如圖3 所示。
圖3 可視化商城構建應用頁面展示圖
圖3 中,左側組件列表中包含頁面中常用的商城頁面結構,包括標題,文字段介紹詳細內容,輪播圖,魔方柵格顯示圖片等。用戶可以在組件列表中拖拽需要的功能,會在中間預覽畫布模塊中顯示相應的部分,并在右側組件屬性控制模塊中調整具體的屬性。
在應用的構成組件列表中,每一個組件都可以使用JSON 數(shù)據(jù)格式詳細地描述該組件的信息。應用過程中組件信息通過操作傳入后,應用解析組件屬性數(shù)據(jù),生成相應的該組件的屬性控制面板。例如一個商品標題,其構造是一個基礎的Form 表單,其中包含屬性有標題(label),類型(type),值(value),占位符(placeholder)等屬性,以代碼的形式展示為:
此標題為基礎類型的組件,更復雜的一系列信息,也可以通過組合形式,把每一個小組件為一個對象或者數(shù)組,多個組件嵌套形成大的復合類型組件。
本文介紹的虛擬DOM 技術,能夠在頁面頻繁變動需要重新渲染頁面時,能夠高效地定位到發(fā)生變動的節(jié)點處,完成頁面的渲染。虛擬DOM 能夠高效地定位需要修改的節(jié)點并完成渲染。因此,虛擬DOM 是一種提升渲染速度的有效手段。但是在頁面更新并不頻繁時,渲染速度只能和直接進行DOM 操作的方案旗鼓相當,甚至頁面變動節(jié)點數(shù)量特小時,渲染速度相對較弱。所以在實際項目開發(fā)過程中,要根據(jù)產(chǎn)品頁面的需求,決定是否選擇使用虛擬DOM 技術。如果只是單純的靜態(tài)展示頁面,不具有過多的交互功能和節(jié)點變動時,使用直接操作DOM 樹的方案更加方便;若頁面包含文檔過多且頻繁更新,選擇使用虛擬DOM 技術則更加具有優(yōu)勢。