校麗麗 楊 雷 吳 玨
(西南科技大學計算機科學與技術學院 四川綿陽 621010)
隨著Web技術的快速發展和移動互聯網時代的到來[1],越來越多的數據處理和業務邏輯處理開始偏向于前端,使得前端對性能的要求越來越高,傳統的Web技術已經不能滿足用戶需求。傳統的Web技術操作對象是DOM(Document Object Model)[2-3],即文檔對象模型。DOM以一種獨立于平臺和語言的方式訪問和修改一個文檔的內容和結構,是表示和處理一個HTML或XML文檔的常用方法[4]。DOM樹是由頁面中的標簽創建而成[5],其結構在一定程度上反映了頁面的內容及內容之間的關系[6]。DOM操作繁瑣復雜,當DOM樹結構、元素的幾何屬性、窗口大小以及元素內容發生變化時,會引起DOM的重繪和回流,并且在操作過程中,也會出現以下幾個問題:
(1) 操作復雜、易出錯。DOM樹操作需復雜選擇器,每次操作DOM樹,需清楚記得DOM節點的id或者class。
(2) 兼容性較差。在動態網頁中,元素綁定和刪除事件的方法不同,在IE中綁定和刪除事件的方法分別是attachEvent()和detachEvent();而在FireFox中綁定和刪除事件分別為addEventListener()和removeEventListener()。
(3) 渲染速度緩慢,浪費資源。對于一個數據很大的列表,若只有一條數據變化或一個DOM節點的尺寸發生變化的情況,整個DOM樹需重新編譯和渲染,降低其渲染速度,浪費大量資源。
(4) 擴展DOM屬性和數據處理方法存在較大的局限性。
針對以上問題,本文提出一種基于數據驅動模型[7]的VirtualDOM樹的構建方法,此方法操作對象不是DOM節點,而是數據,通過數據來控制渲染、指令和表達式擴展DOM功能,增強數據驅動的能力,提高DOM節點靈活性、開發效率和應用性能。
數據是程序的核心,代碼的實現總是和數據結構緊密相關。在軟件開發過程中,數據驅動是盡可能將復雜的設計從程序代碼轉移至數據,從而降低程序設計的復雜度。數據驅動模型以數據為中心,使視圖處于從屬地位。數據驅動模型要求在編程時將模板代碼和數據結構劃分清楚。在改變程序邏輯的時候,只需修改數據,而不需修改模板代碼,實時反映數據的真實變化。相對于傳統的程序邏輯解決問題,使用數據驅動模型具有以下優點:
(1) 易修改。當增加新的邏輯時,只需修改數據,不需修改模板代碼。
(2) 控制復雜度。通過把程序邏輯的復雜度轉移至更容易處理的數據中來,從而達到控制復雜度的目標。
(3) 隔離變化。當程序邏輯發生變化,只需修改邏輯代碼,并不影響模板代碼,從而實現隔離。
(4) 實現重用。在開發過程中,會出現部分邏輯相同,只是處理函數不同的情況,對相同代碼進行提取,實現代碼重用。
指令的作用是操作DOM元素節點。將指令綁定在DOM元素節點上時,會給綁定的DOM元素節點添加一些特殊行為,因此可將其視作特殊的HTML屬性。表達式是使用雙重大括號(“{{}}”)綁定的JavaScript[8]代碼塊,當表達式的值改變時,將其產生的連帶影響響應式地作用于DOM。
指令一般分為內置指令和自定義指令兩種。內置指令是前端框架定義好的指令,可直接使用。自定義指令即用戶自己定義的指令,其作用是擴展元素屬性、操作DOM更加簡單。常見的內置指令有以下幾種:
(1) 條件判斷指令。根據其后表達式bool值來判斷插入或刪除元素。
(2) 條件渲染指令。與條件判斷指令類似,都是判斷元素是否顯示。不同的是,條件渲染指令無論其后表達式的值為true或false,元素都會存在于HTML代碼中,而條件判斷指令只有值為true時,其元素才會存在于HTML代碼中。
(3) 循環指令。基于一個數組渲染一個列表,類似于JavaScript遍歷。
為解決傳統DOM所存在的問題,采用基于數據驅動模型的VirtualDOM樹提高編譯、渲染性能以及擴展更多DOM屬性和數據處理方法。VirtualDOM是輕量級JavaScript對象,其執行在JavaScript引擎[9]中。VirtualDOM的生成給DOM帶來以下幾個優點:
(1) 標簽之間的空格在VirtualDOM創建時就被排除,不會帶來意外的空白。
(2) 元素的字符串被自動轉義,不會容易導致代碼注入。
(3) 模塊化易實現,從而實現代碼共享。
VirtualDOM相對傳統DOM操作有以下幾個優點:
(1) 資源浪費少、操作簡單,處理速度高。
(2) 無需擔心兼容性問題。
(3) 通過擴展屬性(指令)和數據處理方法(表達式)擴展DOM功能,提高DOM靈活性。
對復雜的DOM結構,提供一種方便的工具,進而最小化地操作DOM,是VirtualDOM的核心思想。VirtualDOM樹是在加載數據時進行創建,在VirtualDOM樹創建過程中,需要解決以下關鍵技術:
(1) 初始化數據initData(data),其中data表示模型的數據。
(2) 判斷視圖類型。若為子視圖,通過get(args)獲取VirtualDOM的父容器,并將其子節點轉移至VirtualDOM;若為父視圖,則獲取body容器,轉移其子節點。
get(args)定義如下:
get(selector,findAll,pView)
其中,selector表示選擇器,findAll表示是否獲取所有,默認為false,pView表示的是父對象。
VirtualDOM樹具體創建步驟如下:
(1) 創建VirtualDOM根節點;
(2) 檢查是否需要加載模板文件,若存在則加載模板文件;
(3) 把模塊對應的DOM節點及其子節點轉移到VirtualDOM中;
(4) 把模板文件或模板字符串內容統一追加至VirtualDOM中;
(5) 將VirtualDOM綁定到對應模塊。
VirtualDOM樹的編譯和渲染是可視化呈現最重要的一步,其速度直接影響應用性能及用戶體驗。
編譯是利用編譯程序從源語言編寫的源程序產生目標程序的過程。但本文所提出的編譯與C,Java編譯不同,本文所提出的編譯是將JavaScript代碼編譯成前端框架能夠識別的代碼。由上述可知VirtualDOM樹的創建步驟,但是前端框架代碼并不識別,因此需將VirtualDOM進行編譯成前端框架能夠識別的代碼。
在編譯階段,提供統一編譯接口compile,所有的VirtualDOM編譯都需要調用接口compile。編譯是一個迭代的過程,compile第一步檢查VirtualDOM是否已編譯,若已編譯,則不再編譯,只需進行渲染。
在編譯階段,需要解決以下關鍵技術:
(1) 處理屬性值為表達式的指令。使用getAttrsByValue(args)獲取屬性列表,將帶有表達式的屬性保存至數組。
(2) 初始化指令集。初始化指令集接口為initViewDirectives(el),el表示視圖view。
(3) 遍歷待編譯的Element的孩子節點,進行文本節點、注釋以及元素節點的處理。
VirtualDOM編譯流程如圖1所示。

圖1 VirtualDOM編譯流程Fig.1 The compiling process of VirtualDOM
傳統的DOM樹修改數據之后都需重新編譯,不僅浪費資源,還會出現卡頓現象,降低用戶體驗效果。采用數據驅動模型以及VirtualDOM,實時反映數據的真實變化,簡化開發流程,提高開發效率和用戶體驗度。
渲染不僅是將DOM樹中的節點進行繪制[10],也是頁面進行可視化呈現的最重要的一步,其速度直接影響頁面的可視效果。在渲染時,使用DocumentFragment進行緩存操作,使操作元素進行了“離線”處理,減少頁面回流和重繪。對一個HTML文件,渲染主要分為以下幾步:
(1) 解析HTML并構建VirtualDOM樹。瀏覽器采用自上而下的方式解析HTML,在解析的過程中構建VirtualDOM樹。
(2) 將CSS樣式應用至VirtualDOM節點。
(3) 布局。布局是一個遞歸的過程,從根節點開始,遞歸遍歷子節點,并計算每個節點的大小和位置信息。
(4) 繪制。將樹繪制在顯示屏上。對于每個節點,繪制順序如下:①背景顏色;②背景圖片;③邊框;④子節點;⑤輪廓。
不同的渲染引擎,其渲染流程不同,以Webkit為例,其主要過程如圖2所示。

圖2 Webkit渲染主要過程Fig.2 The main process of webkit rendering
render(container,data)是渲染提供的接口,其中container表示容器,data是數據。在渲染VirtualDOM過程中,需解決以下幾個問題:
(1) 判斷視圖是否存在。若不存在,調用getView(args)獲取視圖。
(2) 判斷是否可以找到視圖。若找不到視圖,直接返回false,不再進行VirtualDOM的渲染。
(3) 若視圖存在,判斷其孩子節點的長度是否為0(為0表示沒有被渲染)。若為0,克隆VirtualDOM,調用renderDOM(args)將克隆后的所有節點渲染至視圖和所有的子節點復制到視圖,并設置已渲染的標志。若孩子節點不為0,則從視圖開始渲染,即發生變化的數據對象對應的DOM節點及其孩子節點。數據發生變化主要有兩種情況:①表達式計算;②指令值發生變化。render渲染流程如圖3所示。
為驗證基于數據驅動模型的VirtualDOM樹構建方法的高效性,實驗基于傳統DOM操作與基于數據驅動模型的VirtualDOM樹的構建,并通過不同的DOM節點數,對頁面的代碼行和編譯、渲染速度進行統計,對比它們的差異。實驗中使用的2款不同渲染引擎的測試瀏覽器詳細配置見表1。

表1 測試瀏覽器配置Table 1 The settings of testing browser

圖3 VirtualDOM渲染流程Fig.3 The rendering process of VirtualDOM
代碼行:實現相同的應用和效果,代碼行越少,開發者需要做的工作越少,開發速度越快。
編譯和渲染速度:在不同開發模式下,對于相同的數據源,相同頁面數據編譯和渲染完成所需要的時間。速度越快,用戶體驗感越好。
在驗證過程中,實現了注冊(register)、商品列表(commodity)的頁面。為排除網絡因素對應用性能表現的影響,實驗過程中所用的數據均為本地JSON[11]格式數據,圖片和文字信息均保存在本地。圖4、圖5是應用運行在Chrome上的效果截圖,其中圖4是注冊頁面,圖5是商品列表頁面。
圖6是實現2個頁面,采用不同開發模式,開發者需要實現的javaScript代碼行數,只包括開發時需要開發者自己編寫的代碼,不包含基礎庫的引用。

圖4 注冊頁面運行效果Fig.4 The running effect of registration page

圖5 商品列表頁面運行效果Fig.5 The running effect of commodity page

圖6 開發代碼量統計Fig.6 The statistics of development code
從圖6可以看出,基于數據驅動模型,開發者需要實現的代碼量均比原生javaScript少。主要原因在于基于數據驅動模型開發的應用可以擴展DOM屬性和數據處理方法,提高DOM節點靈活性。對于注冊頁面,需要大量的驗證工作,比如郵箱、電話等。使用validity指令可對其進行直接校驗,無需復雜的javaScript代碼進行選擇并操作。在商品列表頁面,使用repeat指令對數據進行循環,而無需使用for,forEach等,減少javaScript代碼量,提高開發效率。
圖7-圖9顯示了傳統DOM和基于數據驅動模型的VirtualDOM樹構建兩種模式下開發的應用,運行在Chrome,加載不同數據量的頁面,第一次加載、修改一條數據、修改全部數據時渲染時間的累積統計對比,數據量分別為50條、100條、500條和1 000條。

圖7 第一次加載時間統計Fig.7 The time statistics of first loading

圖8 修改一條數據時間統計Fig.8 The time statistics of modifying a piece of data

圖9 數據全部修改時間統計Fig.9 The time statistics of modifying all of data
從圖中可以看出,基于數據驅動模型的VirtualDOM樹構建方法搭建的應用,其渲染時間比原生DOM渲染時間短,其原因是在第一次加載時,VirtualDOM的執行在javaScript引擎中,開銷較小;修改數據時,使用數據驅動模型,將復雜的邏輯轉移至數據,控制其復雜度,實時反映數據的真實變化。基于原生的應用,每次進行數據修改時,都需要進行選擇、綁定事件、數據處理等步驟,所以其修改數據的渲染時間都比較長。圖10是基于Chrome,Safari兩款不同渲染引擎對原生DOM和基于數據驅動模型的VirtualDOM樹構建應用進行渲染所需時間的結果對比,數據量為100條。

圖10 基于Chrome,Safari時間統計Fig.10 The time statistics based on Chrome and Safari
從圖10可以看出,基于同一種方法開發的應用,在不同渲染引擎的瀏覽器上運行,頁面的渲染所需時間不同,即瀏覽器本事的渲染引擎性能對應用性能有影響。
根據上述實驗可以得出以下兩點:第一,實現相同的功能,基于數據驅動模型的VirtualDOM樹的構建方法的開發代碼量比原生應用少;第二,在相同配置的設備下,基于數據驅動模型的VirtualDOM樹構建方法的編譯和渲染速度比原生DOM快。在數據量較小的情況下,兩者的差別較小。隨著數據量的增加,兩者之間的差距逐漸增大。
為降低Web應用開發難度、提高開發效率,本文提出一種基于數據驅動模型的VirtualDOM樹的構建方法。為實現數據雙向綁定,采用數據驅動模型,以實現實時顯示數據真實變化。采用輕量級JavaScript對象——VirtualDOM模擬真實DOM,提高頁面編譯和渲染速度,加快開發速度,縮短項目周期。通過擴展DOM屬性和數據處理方法,擴展DOM功能,提高DOM節點靈活性。實驗結果表明,與傳統DOM樹相比,基于數據模型的VirtualDOM構建方法,其渲染速度更快、應用性能更高。但是VirtualDOM的執行在JavaScript引擎中會占用部分內存,因此,優化VirtualDOM對內存的占用是下一步研究的重點。
[1]SHAHZAD F. Modern and responsive mobile-enabled web applications [J]. Procedia Computer Science, 2017, 110:410-415.
[2]KNOTT S D, LAIRD J A, WALTERS R J. Dynamic rendering of a document object model, EP2642718[P]. 2013.
[3]FROLIN S O, GUANPENG L, KARTHIK P,et al. Automatic fault localization for client-side JavaScript [J]. Softw. Test. Verif. Reliab.,2016,26(1):28-30.
[4]李景. 基于DOM樹信息抽取的移動網站開發研究[D]. 山東青島:中國海洋大學, 2011.
[5]丁寶瓊, 謝遠平, 吳瓊. 基于改進DOM樹的網頁去噪聲方法[J]. 計算機應用, 2009, 29(b06):175-177.
[6]羅明宇, 凌捷. 基于DOM樹序列值比對的SQL注入漏洞檢測[J]. 計算機工程與設計, 2015,(2):350-354.
[7]LIJUAN HUANG. Analysis on e-consumers’ purchasing behavior based on data-driving model[J]. Journal of Networks, 2011, 6(12):1713-1718.
[8]HAFIZ M, HASAN S, KING Z, et al. Growing a language: An empirical study on how (and why) developers use some recently-introduced and/or recently-evolving JavaScript features[J]. Journal of Systems & Software, 2016, 121:191-208.
[9]余啟洋, 桑楠, 郭文生. 嵌入式瀏覽器JavaScript引擎的研究與設計[J]. 計算機應用與軟件, 2014,(5):251-255.
[10] KIM D, LEE C, LEE S, et al. Parallelized sub-resource loading for web rendering engine[J]. Journal of Systems Architecture, 2013, 59(9):785-793.
[11] 高靜, 段會川. JSON數據傳輸效率研究[J]. 計算機工程與設計, 2011, 32(7):2267-2270.