在Web應(yīng)用越來越關(guān)注用戶體驗的今天,傳統(tǒng)的HTML應(yīng)用已經(jīng)不能滿足開發(fā)人員和終端用戶的需求。OpenLaszlo作為當(dāng)今主流的RIA(Rich Internet Application)的應(yīng)用平臺,在進入開源社區(qū)之后顯示出了更大的活力。Laszlo的技術(shù)基于XML和JavaScript來構(gòu)建RIA程序,為Web開發(fā)人員提供了一種簡潔快速的編程模式,并且給終端用戶以更加動態(tài)的交互式體驗。
OpenLaszlo的SDK(Standard Development Kit)由一個用Java編寫的編譯器、一個運行時的JavaScript庫和一個可選的Java Servlet構(gòu)成,如圖1.1所示。開發(fā)OpenLaszlo的步驟非常簡單:編輯、保存和刷新源文件即可。開發(fā)人員可以使用任何文本編輯器來編輯源文件,并且將其對應(yīng)的URL鍵入瀏覽器。OpenLaszlo服務(wù)器自動地將文件編譯成一個Flash文件,然后瀏覽器將其展示出來。
?
?
OpenLaszlo應(yīng)用由LZX的文件組成。LZX是一種標準驅(qū)動的XML和JavaScript描述性的語言,它使得上述聲明式的(declarative)、基于文本的開發(fā)流程變?yōu)榭赡堋A斜?.2展示了一段簡單的OpenLaszlo程序代碼,它定義了一個按鈕,用戶在按下之后該按鈕的位置會向右移動一段固定的距離。
<canvas height="30">
<button onclick="animate('x', 100, 1000, true)">
Move me
</button>
</canvas>
|
?
在下一章,我們將根據(jù)OpenLaszlo官方的開發(fā)指南,構(gòu)建一個數(shù)據(jù)驅(qū)動的應(yīng)用程序,并對其進行深入的分析和調(diào)試。
?
|
|
| ? |
?
?
為了更加清楚地說明我們的主題,我們根據(jù)OpenLaszlo的官方軟件開發(fā)指南[1],擴展了其中通訊錄的示例。這個應(yīng)用提供了一個功能齊全的聯(lián)系人列表,它列出了所有的聯(lián)系人,并允許用戶對聯(lián)系人添加、刪除和更新。唯一不同的是,我們的程序為用戶提供了更多的選項,包含了更多的數(shù)據(jù)。圖2.1展示了該程序的界面。
由于聯(lián)系人的功能和教程上的基本相同,我們使用了和OpenLaszlo指南中相同的方法來實現(xiàn)它。列表2.2描述了應(yīng)用中一個類contactview的部分代碼。
列表2.2 聯(lián)系人視圖(contactview)的源代碼
<class name="contactview" extends="view" visible="false" x="20"
height="180">
<simplelayout axis="y" spacing="5" />
<view layout="axis:x; spacing: 10">
<text y="10">First Name:</text>
<edittext name="firstName" datapath="firstName/text()" y="10"/>
<text y="10">Last Name:</text>
<edittext name="lastname" datapath="lastName/text()" y="10"/>
</view>
<view>
<text x="0" y="10">Gender:</text>
<radiogroup layout="axis: x" x="80" y="12" datapath="gender" >
<attribute name="genderv" type="string" value="$path{'text()'}"
/>
<method event="ondata">
this.selectItem(this.getAttribute('genderv'));
</method>
<radiobutton value="'M'" text="Male" />
<radiobutton value="'F'" text="Female"/>
</radiogroup>
<text x="195" y="10">Country:</text>
<mycombobox x="275" y="10" width="105"
datapath="country/text()">
<textlistitem value="${this.text}"
datapath="timedata:/time/day/item/text()"/>
</mycombobox>
</view>
</class>
|
?
此外,雖然應(yīng)用的數(shù)據(jù)存儲在本地機器的XML文件中,但如列表2.3所示,我們對數(shù)據(jù)集的type和request屬性做了設(shè)置,使應(yīng)用程序在運行時才能夠得到數(shù)據(jù)。在這種情況下,我們能夠模擬OpenLaszlo的客戶端從遠程的服務(wù)器中獲得數(shù)據(jù)的情景。
<dataset name="countrydata" request="true" type="http" src="countries.xml"/>
|
?
完成上述應(yīng)用之后,性能問題迅速地顯現(xiàn)出來。系統(tǒng)主要在以下三方面表現(xiàn)出了性能的瓶頸:
1. 程序初始化的時間很長。當(dāng)列表達到30個聯(lián)系人條目的規(guī)模時,程序就會花費很長時間來顯示整個列表。在程序裝載的過程中,這些條目逐條緩慢地顯示出來。而在此期間,用戶幾乎不可能進行任何操作。
2. 下拉框(combobox)的初始化時間長度令人難以接受。當(dāng)下拉框的選項非常多時,由于控件會等待列表初始化完畢后才變?yōu)榭梢姡@將會耗費大量的時間和內(nèi)存。
3. 刪除功能的表現(xiàn)也不盡如人意,尤其在用戶嘗試刪除位于頂端的條目。當(dāng)一個條目被刪除時,在其之下的條目將會被完全地刷新。這樣的重畫界面也引發(fā)了嚴重的性能問題。鑒于以上的性能問題,我們將逐步討論如何解決這些問題。在第三章中,我們會闡述一些能夠提高性能的普遍原則,并應(yīng)用到本章所演示的程序里。進一步的,第四章將描述本文所涉及的實驗方法,并且向讀者展現(xiàn)比較實驗的結(jié)果。
?
|
|
|
?
在默認情況下,OpenLaszlo會在加載頁面時對所有的元素全部進行初始化。無論這些元素是可見或不可見的,它們都會被實例化。同時,OpenLaszlo提供了initstage屬性來控制何時執(zhí)行節(jié)點的init方法以及發(fā)送oninit事件的時機。initstage是LzNode的屬性,換言之,它幾乎可以被所有的元素繼承并使用,它有五種可選的屬性值[2]:
-
immediate
除非該實例的所有子節(jié)點被創(chuàng)建,否則其他代碼都不得運行。也就是說,初始化是實例化的最后一個階段。 -
early
在視圖(view)和它的子節(jié)點被創(chuàng)建后,立即調(diào)用init方法。 -
normal
系統(tǒng)缺省值。Init方法在初始化父節(jié)點的工作完成后被調(diào)用。 -
late
在系統(tǒng)空閑時(idle)初始化節(jié)點。用戶可以通過檢查isinited屬性來確認節(jié)點是否被初始化完畢。如果想在某一時刻強制節(jié)點初始化,可以調(diào)用completeInstantiation方法。 -
defer
在該設(shè)置下,除非用戶顯式地調(diào)用completeInstantiation,否則節(jié)點將不會被初始化。
不難看出,使用late和defer的節(jié)點,在執(zhí)行init方法以及發(fā)送oninit事件時,并不一定被初始化完畢。因此,它們非常適用于延緩OpenLaszlo節(jié)點的初始化時間。對一些在頁面初次加載時不可見的節(jié)點,我們可以使用initstage = defer來抑制初始化,在觸發(fā)其可見的事件上按需調(diào)用completeInstantiation。這樣既可以減少頁面初始化的時間,又可以減少很多不必要的初始化。因為對用戶而言,很多不可見的元素是不需要被加載進系統(tǒng)的。
具體到我們的通訊錄應(yīng)用中,顯示聯(lián)系人細節(jié)的視圖(contactview)完全符合上述的條件。于是,我們將其initstage的屬性設(shè)為defer,并且重寫了其父節(jié)點的onclick事件,使得只有在用戶點擊了條目后,細節(jié)視圖才會占用系統(tǒng)的資源,按需地被初始化。列表3.1描述了具體的代碼。
<view id="newEntryView">
<text text="New Entry..." >
<method event="onclick">
parent.newContactView.setVisible(!parent.newContactView.visible);
//在點擊時完成初始化
parent.newContactView.completeInstantiation();
</method>
</text>
<contactview name="newContactView"
datapath="newcontact:/contact"
initstage="defer"> <!--在頁面初次加載時不初始化contactview-->
<button width="80" x="300" text="Add" />
</contactview>
|
?
用戶界面中,經(jīng)常存在實際條目比展示給用戶的條目多的列表。OpenLaszlo為這種情況在baselist、basecombobox等節(jié)點中定義了dataoption屬性。當(dāng)dataoption取lazy值時,列表的條目(listitem)將會使用惰性復(fù)制,即只復(fù)制需要顯示的條目。通訊錄中表示國家的下拉框有近200個選項,就屬于這種情況。在列表3.2中,我們自定義了一個下拉框類,并附上了它的使用示例。這樣,即使有200個數(shù)據(jù)項,系統(tǒng)也只復(fù)制了5個textlistitem的視圖。
<class name="mycombobox" extends="combobox" editable="false"
shownitems="5"
dataoption="lazy" />
<mycombobox id="country" x="275"
width="105"
datapath="country/text()">
<textlistitem datapath="countrydata:/countries/country/text()"
value="${this.text}" />
</mycombobox>
|
?
值得一提的是,我們在<textlistitem>中直接定義了datapath屬性,因此它繼承了父節(jié)點dataopiton = lazy的特征。如果在<textlistitem>下單獨定義datapath元素,那么我們還必須將其replication屬性設(shè)為lazy,如表3.3所示。
列表3.3 單獨聲明datapath的textlistitem
<mycombobox >
<textlistitem value="${this.text}" >
<datapath xpath="countrydata:/countries/country/text()"
replication = "lazy" />
</textlistitem>
</mycombobox>
|
?
事實上,OpenLaszlo使用惰性復(fù)制的列表使用LzLazyReplicationManager而不是缺省的LzReplicationManager來控制視圖。后者在視圖的datapath和多個datanode匹配時,為每一個匹配都創(chuàng)建一個視圖;而前者出于顯示數(shù)據(jù)的考慮,只創(chuàng)建足夠數(shù)量的視圖。本文的例子中,通訊錄的條目過多時(如超過100條),也可以考慮使用lazy的屬性使初始化時間變快。
假使OpenLaszlo應(yīng)用使用了數(shù)據(jù)復(fù)制,而且這些數(shù)據(jù)在運行時改變的話,默認的LzReplicationManager會將數(shù)據(jù)改變所對應(yīng)的視圖銷毀,然后重新創(chuàng)建它們。顯而易見,如果數(shù)據(jù)集非常大,這樣的調(diào)整策略會導(dǎo)致用戶界面嚴重的反應(yīng)遲緩。如第二章所述,我們的通訊錄應(yīng)用在刪除位于列表頂端的記錄時,就會出現(xiàn)明顯的延遲。
為了解決上述問題,我們可以將匹配多個數(shù)據(jù)節(jié)點的datapath中的pooling屬性設(shè)為true。設(shè)置之后,LzLazyReplicationManager只是將改變了的數(shù)據(jù)重新指向已經(jīng)被創(chuàng)建的視圖。這樣用戶界面所反映出的數(shù)據(jù)更新速度會明顯加快,具體的應(yīng)用見列表3.4。
<view>
<datapath xpath="dset:/phonebook/contact" pooling="true" />
<simplelayout axis="y" />
<view name="list" >
<!-- more... -->
</view>
</view>
|
?
|
|
|
?
最后,我們將對本文提及的實驗進行性能的監(jiān)測和調(diào)試。根據(jù)上文的原則,我們采用OpenLaszlo 3.3.3,對性能優(yōu)化前后的結(jié)果進行比較。表4.1展示了實驗的具體配置。
表4.1 實驗環(huán)境的配置
| CPU | 內(nèi)存大小 | Total paging space | 瀏覽器類型 |
| 1698MHz | 512MB | 1.22GB | Mozilla Firefox 1.5.0.4 |
測量OpenLaszlo代碼的性能分為兩種:加載時間和響應(yīng)時間。前者說明了OpenLaszlo的應(yīng)用在多久之內(nèi)被初始化,而后者則是衡量程序能夠響應(yīng)用戶動作的敏捷程度,比如在通訊錄應(yīng)用中完成"刪除"功能的時間長度。對于這兩種時間,我們都在程序開始和結(jié)尾記錄時間,然后將兩者相減,得到最后的結(jié)果。列表4.2展示了這種方法的實現(xiàn)代碼。
<button width="80" text="Delete">
<method event="onclick">
var pre = (new Date).getTime(); //記錄開始執(zhí)行時間
parent.parent.parent.datapath.deleteNode();
var cur = (new Date).getTime(); //記錄結(jié)束時間
debug.write(cur - pre); //輸出
</method>
</button>
|
?
我們分別對通訊錄中有3條、9條和30條記錄的情況做了比較。我們逐項應(yīng)用上述的原則:所有表示時間的實驗數(shù)據(jù)單位為毫秒(ms)。最后的結(jié)果由10次操作的平均時間得到。首先,我們將 "initstage = defer"前后的初始化時間的比較列在表4.3。可以看到,在聯(lián)系人的細節(jié)視圖不被加載的時候,初始化的時間有了明顯的加快。
表4.3使用defer的性能比較
| 記錄數(shù)目 | initstage = defer(ms) | initstage = normal(ms) | 降低幅度(%) |
| 3 | 268.4 | 3277.8 | 91.82 |
| 9 | 433.6 | 10816.8 | 95.99 |
| 30 | 955.2 | 54734.7 | 98.25 |
其次,表4.4展示了在使用"pooling"前后的響應(yīng)時間。
表4.4 使用pooling的響應(yīng)時間比較
| 記錄數(shù)目 | pooling = true(ms) | pooling = false(ms) | 降低幅度(%) |
| 3 | 28.00 | 136.14 | 79.43 |
| 9 | 77.00 | 728.00 | 89.42 |
| 30 | 467.67 | 3079.25 | 84.81 |
最后,本文描述"lazy"選項的效果,如表4.5所示。不難看出,"lazy"選項與上述的選項不同,沒有隨著記錄的增多而對性能有顯著的改善。顯然,這是因為"lazy"針對的是單個更新視圖的初始化時間,和總體記錄的條數(shù)沒有明顯的關(guān)系。
表4.5 使用lazy的性能比較
| 記錄數(shù)目 | dataoption = true(ms) | dataoption = none(ms) | 降低幅度(%) |
| 3 | 838 | 7213.6 | 88.38 |
| 9 | 852 | 7344.5 | 88.40 |
| 30 | 961.4 | 8587.1 | 88.80 |
?
|
|
|
?
本文為OpenLaszlo的開發(fā)者提供了一些提高程序性能的技巧,具體包括:延緩初始化的時間、惰性復(fù)制和緩存數(shù)據(jù)。我們通過擴展OpenLaszlo開發(fā)指南中的示例,向讀者展示了一個略微復(fù)雜的通訊錄應(yīng)用。以其為場景分析了系統(tǒng)的性能瓶頸,將作者所總結(jié)出的技巧應(yīng)用于其上。最后,我們還對每個具體的原則做了實驗,比較了性能的差異。從我們的實驗中可以看到,本文所提及的原則對性能的提高有著顯著的作用。相應(yīng)的用戶體驗也有了明顯的提升,達到了用RIA開發(fā)的目的。
在今后的工作中,我們將進一步優(yōu)化這個示例,使其成為一個能和后臺Java Server進行交互的應(yīng)用,并開發(fā)出相應(yīng)的OpenLaszlo組件。更進一步的,我們會在此基礎(chǔ)上為應(yīng)用添加更多(諸如全球化)的特性。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

