最近一直在使用 Flex3 對原有項目進行重構和 bug 修改。遇到不少性能問題,分析發現由于 Flex 在和 Servlet 交互時使用了大量的 XML 作為傳輸格式,導致某些功能在處理 XML 時非常的慢,甚至還 Error #1502: A script has executed for longer than 15 seconds。讓人痛不欲生!
和 RIA Meeting 組織者 lwz7512 交流后,他建議使用 BlazeDS 來代替 XML 操作。隨著對 BlazeDS 的漸漸了解,的確能解決不少性能問題。Adobe 的 Flex 技術傳道士 James Ward 在 BlazeBench: Why you want AMF and BlazeDS一文中詳細比較了利用 BlazeDS 所帶來的性能提升,下圖是 James Ward 寫的性能測試工具。
通過上面的測試數據發現,正如 BlazeDS 官方網站所提到的:在使用 AMF3 作為傳輸協議后,Flex 和后臺交互的性能大約提高了10倍。面對這一結果,想必大家很興奮,看來是時候用 BlazeDS 來替換 XML 了。不過問題并不是這么容易就解決了,由于 BlazeDS 在 2007年12月12日才正式開源發布,而在這之前項目都是以 XML 作為傳輸格式(當然也沒用GraniteDS),并且 Flex 代碼中處處可見對 XML 的操作,要對這樣的代碼進行重構......難。
要解決 XML 處理的性能問題。就應該好好的利用 E4X,盡量避免在解析 XML 的過程中使用循環。這里介紹幾篇文章讓大家了解下《E4X:出色的 JavaScript》、《E4X 教程》、《AS3中新的XML處理方法 – E4X》。E4X給我最大的便利就是..運算符。思考下面的XML:
var?myXML:XML?=???????????????? < groups? name ="大組" > ???????????????????? < group? name ="小牛組" > ???????????????????????? < person? fullname ="rosenjiang" /> ???????????????????????? < person? fullname ="abc" /> ???????????????????? </ group > ???????????????????? < group? name ="柴雞組" > ???????????????????????? < person? fullname ="rosenjiang" /> ???????????????????? </ group > ???????????????????? < group? name ="柴鴨組" > ???????????????????????? < person? fullname ="rosenjiang" /> ???????????????????????? < person? fullname ="rosen?jiang" /> ???????????????????? </ group > ???????????????????? < group? name ="獨立大隊" > ???????????????????????? < person? fullname ="rosenjiang" /> ???????????????????? </ group > ??????????????????? </ groups > ;
要得到所有屬性fullname是”rosenjiang”的person節點的個數怎么做?在沒詳細了解 E4X 之前,我會用 myXML.group 操作得到 group 的 XMLList 集合,然后再用循環去找尋每個 group 中 person 節點屬性 fullname 為”rosenjiang”的數據:
上面的寫法的確很傻,下面是改進之后的代碼,關鍵部分只有一行:
通過合理使用 E4X 語法,順利的避免了循環帶來的性能問題。過了幾天,來個新的需求,需要統計出在這個 XML 中有幾個不同姓名的 person。思考片刻,我可不可以用眼睛數出來啊?這里有 3 個...... 好吧,看來又是循環問題,第一個想到的是用兩個嵌套 for 循環來進行排除處理,這是最直觀的想法......
下面我介紹下如何用 ArrayCollection 并只使用一個循環來計算個數。由于 Flex 里面不支持 Map 類型,而我 Google 了一圈,且 RIACN 論壇上網友的 Map 實現性能都不行,遂打算用 ArrayCollection 模擬 Map 進行操作:
上面代碼沒什么過多解釋,思路是取出一個 fullname 放進 ArrayCollection,然后判定下一個 fullname 是否存在于 ArrayCollection 中,如果存在就跳過,不存在就放進去再取下一個。另外我發現,使用 for each 比單純的使用 for 性能要高一點點。
做了以上的努力后,性能還是低下!怎么辦?看來沒什么辦法了,和你的 boss 談談吧,考慮下進行大刀闊斧重構的可能性。或者能否在超時后給用戶一個提示,讓他操作的數據量少點,需要做的是捕獲超時異常,既 ScriptTimeoutError,請參閱http://www.cs.vu.nl/~eliens/pim/assets/flex3/langref/flash/errors/ScriptTimeoutError.html,進行 try catch 。 Good luck!
Powered by: BlogJava Copyright © Rosen