You are on page 1of 36

Flex Application ਝ૖Ȉ

‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

2004 ԑ 5 Т
Copyright © 2004 Macromedia, Inc. ߳੼‫ܚ‬Ԥ᠌ցȄ
ҏМӇϛ‫֤ܚ‬Ϟၥଉфߒ Macromedia Ҭࠉܻี՗Р෈ᄇܻ‫ܚ‬ଆ፣Ϟដᚠ‫ݲࣼޟ‬Ȅҥܻ Macromedia ҆໸ᄇᡐϽ‫ޟ‬ѿൟ‫ݷޑ‬Ԥ‫ܚ‬ІᔖȂӰԪҏഋϷϚᔖೝ
၌ភ࣏ Macromedia Ϟ‫ܛ‬ᒛȂи Macromedia ζฒ‫߳ݲ‬ᜌӵี՗Р෈Ϟࡣ‫ܚ‬ю౪‫ޟ‬ӈդၥଉ‫ྥޟ‬ጂ‫ܒ‬Ȅ
ҏҩҪਪ༉‫ټ‬୤ՃȄMACROMEDIA ϚᄇҏМӇϛϞӈդ݂Ұ‫ུܖ‬Ұϱৠඪ‫߳ټ‬ᜌȄ
Macromedia џ૖ᄇҏМϛ‫ܚ‬ϭಝϞᄇຫ᏿ԤடցȃடցϞᔖҢȃ୦኿ȃ๿հ᠌‫ڏܖ‬тසኋ଒౰᠌Ȅଶߨ Macromedia оӈդਪ७௲᠌ӫघϞ‫ל‬Ԓ݂ጂඪ
юȂ֏ࠌҏМӇ‫ٮ‬Ϛфߒ࣏ௌඪ‫ټ‬೻‫ٲ‬டցȃ୦኿ȃ๿հ᠌‫ڏܖ‬тසኋ଒౰᠌Ϟ௲᠌Ȅ
Macromedia®ȃMacromedia ኿ᇬȃMacromedia Dreamweaver®ȃMacromedia Flex® Ѕ Macromedia Flash® ࣏ Macromedia, Inc. ӵछ୽Ѕ/‫ڏܖ‬т୽ড়
‫ޟ‬୦኿‫ܖ‬ຝы୦኿ȄҏМӇϛඪЅϞᄂሬϴѧᇄ౰ࠢӪᆎџ૖࣏‫ڏ‬ӨՌ᏿Ԥ‫ޱ‬Ϟ୦኿Ȅ
Macromedia, Inc.
600 Townsend Street, Suite 500
San Francisco, CA 94103
415–252–2000

ii
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

Ҭᓃ

ஈ՗ᄢौ............................................................................................................................... 1

೩ॎюၼհ‫ي‬ԁ‫ ޟ‬Flex ᔖҢแԒ࢜ᄺ ..................................................................................... 2

Flash Player ‫ݧޟ‬ཎ‫ٱ‬໶ ..................................................................................................... 2

ғጂ‫ٺ‬Ң‫ގ‬७଩ညȃ໦ቹ‫ڷ‬ϱ֤໶Ҭ ....................................................................................... 3
避免建立許多容器巢狀層次 ................................................................................................3
絕對定位與調整大小..........................................................................................................4
聰明地使用格線容器..........................................................................................................5
應避免的常見容器重複範例 ................................................................................................7
‫ٺ‬Ң‫۽‬ᒶஈ՗এᡝϽ‫׽پ‬๡ਝ૖.............................................................................................. 9
導覽容器有內建延遲執行個體化 ..........................................................................................9
漸進式版面配置 ..............................................................................................................10
延遲動作........................................................................................................................16
೎౩σ໔‫ޟ‬ၥਟ໱ ................................................................................................................ 16

໷ᄱӴኬܹፒӫ੫ਝ............................................................................................................. 16

‫ٺ‬Ңஈ՗ਢ෈ኺԒႀԙ‫ޟٹ؁‬ਝ૖.......................................................................................... 17

‫׽‬๡ Repeater ‫ސ‬Ӈ‫ޟ‬ਝ૖ .................................................................................................. 18

ᕣ၌ Flex ৤Ұթ݈Ꮲϛ‫ڥפޟ‬ђ૖ .......................................................................................19

ও‫ ׽‬flex-config.xml ಢᄘ೩ۡ ...........................................................................................20

Ԇ‫ ڥ‬Flex ၥਟ݈୛ .............................................................................................................21

‫ٺ‬Ң JSP ኿ᡆ৲................................................................................................................ 23

Ⴑӑጡឍ MXML ᆩॲ ........................................................................................................24

ഋဍᒵ໶............................................................................................................................ 27

ବᄇௌՌϏ‫ ޟ‬Flex ᔖҢแԒ໌՗ਝ૖ཌ፡ᇄϷ‫ ݙ‬................................................................... 27


使用 ActionScript 設定器 ...............................................................................................28
計算應用程式初始化時間..................................................................................................28
使用 getTimer() 計算元件和資料動作的時間.......................................................................29
針對您的 Flex 應用程式進行負載測試................................................................................29
負載測試工具 .............................................................................................................. 29
負載測試範例 .............................................................................................................. 30

Ґ‫ีپ‬৤… .......................................................................................................................... 31

ཎَᇄЛධ......................................................................................................................... 32

ᜰܻհ‫ޱ‬............................................................................................................................ 32

1
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

ஈ՗ᄢौ
Macromedia Flex 是功能強大的平台,提供建立 Rich Internet Application (RIAs)
的能力。不當使用會造成一些區域的效能變差。本文探討其中一些效能問題,並提供
如何運用下列兩個層級,來充份發揮 Flex 應用程式效能的提示:Flex 用戶端和 Flex
展示伺服器 (presentation server)。
Flex 與其他採用該特定編碼的程式設計模型一樣,可能會影響到應用程式在用戶端的
整體效能。本文說明某些會在用戶端影響應用程式效能的 MXML 編碼方式,並展示
加強 Flex 應用程式效能的簡單技術。
其中特別探討如何:
縮短啟動時間
運用延遲執行個體化來改善效能
順暢地播放複合特效
改善重複項物件的效能
處理大量的資料集
對 Flex 應用程式進行效能測試
對於伺服器,本文件的內容包括:
flexconfig.xml 檔與此檔案對效能的影響
Flex 快取模型
有效率地傳送資料至 Flex 用戶端
有效地運用 JSP 附加標籤庫
預先編譯 MXML 頁面
JVM 微調
Flex 部署選項
請注意,本文件中建議的提示並不適用於所有 Flex 應用程式。您必須先分析您應用
程式的結構,並依需求修改建議。若需持續的編碼與概念上的協助,您可使用 Flex
支援論壇
(www.macromedia.com/cfusion/webforums/forum/index.cfm?forumid=60) 和
Flex 開發人員中心 (www.macromedia.com/devnet/flex/)。
亦請注意,為充份運用本文件,您需要具備下列各項:
Macromedia Flex (www.macromedia.com/tw/software/flex/trial/)
Macromedia Flash Player 7
熟悉使用 Macromedia Flex 與 J2EE 應用程式伺服器(Jrun、IBM
Websphere、BEA Weblogic)
一些建立 Flex 應用程式的經驗。(理想狀態下,您應至少已建立過一個簡單的
Flex 應用程式。)

1
೩ॎюၼհ‫ي‬ԁ‫ ޟ‬Flex ᔖҢแԒ࢜ᄺ
理想上,在開發程序的每個階段 - 從應用程式設計到實作乃至於部署 - 中,都應以
效能為主要考量。當建立 Flex 應用程式時,全盤思考您使用的各種容器和元件的選
擇,以確保程式碼是可以維護、組織清楚,而且運作良好。
您可在各種應用程式類型上,使用 Flex 導覽容器(navigator container)
(Accordion、TabNavigator 和 ViewStack)來組織內容。導覽容器組織內容的方
式可以:

將終端使用者的困擾降到最低
展現為以瀏覽器為主的應用程式所設計的良好使用者介面 (UI)
協助效能
尤其 Flex 導覽容器還可協助您輕鬆以不同的子系檢視,來組織內容,並使用延遲執
行個體化,來控制這些檢視的建立工作。在這些子系檢視中組織內容時,在建立每個
子系檢視時都需要一段時間,因為當使用者第一次要求特定子系檢視時,Flex 會建立
此子系檢視。本文稍後的「導覽容器有內建延遲執行個體化」一節說明為什麼 Flex
導覽容器與延遲執行個體化搭配使用時,就能提供較佳的效能,以及如何運用延遲執
行個體化,讓您的應用程式更加強穩。
而儀表板式的應用程式也帶來部署的成功。此種應用程式類型可將內容組織為模組化
的獨立檢視,為應用程式組織提供更具直覺式的方式。和導覽容器一樣,本方式也能
提供不錯的效能,因為當使用者向下切入時,它可使用 Flex 來組織複雜的檢視。
Flex 不需要在幕後調整大小、測量和繪製檢視,所以可以更迅速地建立選取的檢視。

Flash Player ‫ݧޟ‬ཎ‫ٱ‬໶


在使用技術以避免常見效能問題之前,請先確定您已安裝了 Macromedia Flash
Player 7(7.0.14 版或 7.0.19 版)。Flash Player 是多平台用戶端,讓使用者可
用來與 Flash 內容互動。播放器有兩種類型,包括 Flash Player 版本及 Flash
Debug Player 版本(又稱為 fdb)。在開發階段中,最適合使用 Flash Debug
Player 版本,因為它可讓 Flex 進行除錯和設定資料功能。由於大部份的使用者都使
用 Flash Player 版本,所以使用本版本可進行效能微調;使用 Flash Debug
Player 版本來執行 Flex 應用程式無法精確呈現應用程式的效能。在執行 SWF 檔
時,Flash Debug Player 版本會報告追蹤陳述式和警告。此項工作需要執行中應用
程式所需的 ActionScript 處理循環,因此會影響到應用程式的效能。
當您準備要測試應用程式效能時,請確認您已使用 Flash Player 7(發行版本)來執
行應用程式。許多 Flex 應用程式開發人員都會犯這個簡單的錯誤!若要確認 Flash
Player 的版本,請在部署期間所使用的瀏覽器中,執行 Flex 應用程式,然後在瀏覽
器視窗中按滑鼠右鍵。如果您在內容功能表中看到除錯選項,表示您正在執行 Flash
Debug Player 版本。如果您能微調應用程式,以便與 Flash Debug Player 版本執
行時有良好效能,您就可確定您的應用程式與 Flash Player 7 執行時會有相同或更
佳的效能。
若需使用 Flash Debug Player 對用戶端程式碼除錯的相關資訊,請參閱位於網站
www.macromedia.com/devnet/flex/articles/client_debug.html 的
Debugging Client-Side Code in Flex Applications。

2
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

ғጂ‫ٺ‬Ң‫ގ‬७଩ညȃ໦ቹ‫ڷ‬ϱ֤໶Ҭ
影響 Flex 效能的最主要因素,是任意使用容器。因為使用過多的容器會大幅降低應
用程式的效能。這是 Flex 開發人員最常犯的效能錯誤 — 所幸可以完全避免這個錯
誤。之所以會發生效能降低的情況,是因為 Flex 版面配置管理員及其子系會依循調
整大小與測量演算法,來決定 x,y 位置、偏好大小及樣式。而這些計算需要大量資
源;因此這些計算加上運用 Flash Player 來繪製複雜物件的作業,會延緩 Flex 應用
程式在啟動時,或在導覽容器中執行個體化新檢視時的速度。要大幅提高應用程式啟
動速度與加快互動時間的原則就是:避免不必要的容器巢狀結構。
首先,您可能會覺得要找出多餘的容器巢狀結構並不容易。下列各節說明容器巢狀結
構的常見個案,並提供選擇與使用容器的有用秘訣。

ᗗջ࡚ҳ೨ӻৠᏢற‫ޑ‬ቹԩ

最好的方法,就是不要建立超過三層的容器巢狀層次。下列為深層巢狀的範例:
<mx:VBox>
<mx:HBox>
<mx:Form>
<mx:FormItem>
...
...
</mx:FormItem>
</mx:Form>
</mx:HBox>
</mx:VBox>

以及
<mx:Grid>
<mx:GridRow>
<mx:GridItem>
<mx:VBox>
<mx:Button />
</mx:VBox>
</mx:GridItem>
</mx:GridRow>
</mx:Grid>

當您建立容器巢狀時,每個容器執行個體都會在其子系上執行測量與調整大小的演算
法(其中有些會在容器本身上執行,因此測量程序會遞迴執行)。在處理版面配置演
算法,並已計算相關的版面配置值時,Flash Player 就會繪製複雜的物件集合,以構
成整個檢視。藉由除去物件建立時的不必要工作,就可明顯大幅提高應用程式的效能。
通常,建立三層或三層以下的容器巢狀層次,建立時就可產生良好的效果。如果您發
現您建立超過三層的容器巢狀層次,請重新評估您的容器選擇。您也許可以使用不同
的版面配置容器與樣式屬性(例如水平和垂直對齊、邊界、隔板和間距),來產生相
同的版面配置。您可運用邊界和間距,來調整控制項四週,以及控制項邊緣與其父項
容器邊緣之間的空間。您可使用隔板物件來填滿不需要的空間,或在畫面上排列控制
項。您也可以在控制項的容器內,水平或垂直對齊控制項。例如,請參閱圖 1。您不
需使用「格線 (Grid)」容器就可產生此版面配置。

3
ყ 1Ȉ! 您不需使用「格線 (Grid)」容器就可產生此版面配置。

在編寫程式碼時,常會使用「格線 (Grid)」容器來產生此版面配置:
<mx:Grid>
<mx:GridRow>
<mx:GridItem>
<mx:Button label="Visa"/>
</mx:GridItem>
<mx:GridItem>
<mx:Button label="MasterCard"/>
</mx:GridItem>
<mx:GridItem>
<mx:Button label="Diner's Club"/>
</mx:GridItem>
<mx:GridItem>
<mx:Button label="AmEx"/>
</mx:GridItem>
</mx:GridRow>
</mx:Grid>

但是,這會使程式碼增加不必要的大小。事實上,您可輕鬆修改程式碼,讓它可看起
來完全像圖 1。下列程式片段只需較少的程式碼,而且還可以縮短建立時間,並產生
稍微小一點的 SWF 輸出。
<mx:HBox>
<mx:Button label="Visa"/>
<mx:Button label="MasterCard"/>
<mx:Button label="Diner's Club"/>
<mx:Button label="AmEx"/>
</mx:HBox>

活躍的 Flex 社群成員 Steven Webster 在他的 blog 中,詳細列出影響巢狀容器效


能的因素,並提供如何避免多餘巢狀的秘訣,網址為:
www.richinternetapps.com/archives/000042.html。

๘ᄇۡ՝ᇄ፡ᐌσω

Flex 容器類別是相對的版面配置容器,可為您在畫面上安排內容。但是,解譯每個容
器及其子系的大小,以及放置它們的位置等計算作業,都需要大量的資源。以下提供
兩個秘訣,將有助於減少這類的計算:

4
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

硬式編碼物件位置 - 硬式編碼物件位置 (Hard-coding object position) 可節省


許多時間,因為 Flex 版面配置管理員不需在執行時期計算物件位置。如果您使用
此方式,就可使用畫布 (Canvas) 容器。其他容器類型,例如 VBox,並不會使用
此絕對位置。在使用畫布 (Canvas) 容器時,您必須明確指定所有畫布 (Canvas)
子系的 x 和 y 屬性。如果您未設定 x 和 y 屬性,畫布 (Canvas) 容器的子系會在
預設 x,y 座標 (0,0) 上重疊版面配置。如果您希望在調整瀏覽器視窗大小時,調
整應用程式大小,則絕對定位無法發揮正常功能。Macromedia 建議您開始時先
使用相對版面配置容器,然後在通過效能測試後,切換至畫布 (Canvas) 容器。
硬式編碼物件的寬度與高度 - 硬式編碼物件的寬度與高度 (Hard-coding object
widths and heights) 也能節省時間,因為 Flex 版面配置容器在執行時期不需要
計算物件的大小。藉由硬式編碼容器或控制項寬度與高度,您可減輕相對版面配置
管理員的處理量,進而縮短容器與控制項的建立時間。此項技術適用於任何容器或
控制項。

ᖑ݂Ӵ‫ٺ‬ҢਿጣৠᏢ

您可以把格線 (Grid) 容器視為一種多層堆疊的版面配置選擇。格線 (Grid)、


GridItem 和 GridRow 本身都是容器,雖然 GridItem 和 GridRow 僅能與格線
(Grid) 容器搭配使用。只有在控制項必須同時水平和垂直對齊時,才應使用格線
(Grid) 容器。開發人員經常會使用格線 (Grid) 容器,因為他們把它當成類似 HTML
<table> 的標籤。但是,身為 Flex 開發人員,您可以從多種容器中選擇位置物件
(其中有些物件所需的資源會比較少)。但是在 HTML 中,<table> 其實是唯一的
選擇。下列程式碼範例說明使用格線 (Grid) 容器的時機 - 當必須對齊位於不同欄和
列的控制項時(請參閱圖 2):
<mx:Grid>
<mx:GridRow>
<mx:GridItem><mx:TextInput
text="TextInput"/></mx:GridItem>
<mx:GridItem><mx:NumericStepper/></mx:GridItem>
<mx:GridItem><mx:TextInput
text="TextInput"/></mx:GridItem>
<mx:GridItem><mx:NumericStepper/></mx:GridItem>
</mx:GridRow>
<mx:GridRow>
<mx:GridItem><mx:Button label="button"/></mx:GridItem>
<mx:GridItem><mx:DateField /></mx:GridItem>
<mx:GridItem><mx:Button label="button"/></mx:GridItem>
<mx:GridItem><mx:DateField /></mx:GridItem>
</mx:GridRow>
<mx:GridRow>
<mx:GridItem><mx:TextInput
text="TextInput"/></mx:GridItem>
<mx:GridItem><mx:NumericStepper/></mx:GridItem>
<mx:GridItem><mx:TextInput
text="TextInput"/></mx:GridItem>
<mx:GridItem><mx:NumericStepper/></mx:GridItem>
</mx:GridRow>
</mx:Grid>

5
ყ 2Ȉ! 此 UI 最適合用於格線 (Grid) 容器。

下列為一些常見的誤用格線 (Grid) 容器例子:

當您要靠左或靠右對齊同一個容器中的控制項時,使用格線 (Grid) 容器(請參閱


圖 3)。開發人員通常會嘗試使用下列程式碼來這麼做:
<mx:Grid borderStyle="solid" width="400">
<mx:GridRow>
<mx:GridItem horizontalAlign="left">
<mx:Button label="left" />
</mx:GridItem>
<mx:GridItem horizontalAlign="right">
<mx:Button label="right" />
</mx:GridItem>
</mx:GridRow>
</mx:Grid>

但是,使用 HBox 容器與隔板 (Spacer) 物件來填滿不需要的空間,可產生與下列


程式碼片段相同的作用:
<mx:HBox borderStyle="solid" width="400">
<mx:Button label="left" />
<mx:Spacer widthFlex="1" />
<mx:Button label="right" />
</mx:HBox>

ყ 3Ȉ! 您不需要使用格線 (Grid) 容器,就可做到靠左對齊和靠右對齊版面配置。

將格線 (Grid) 容器當成重複項 (Repeater) 物件的子系,但其實使用其他的替代機


制可以達到更好的效果。請參閱圖 4 中的重複項 (Repeater) 物件。

6
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

ყ 4Ȉ! 在重複項 (Repeater) 物件中使用格線 (Grid) 容器來產生此版面配置,會耗用很多資源。

重複項 (Repeater) 物件會使用從 web-service 擷取的標籤,重複大量地填入格線


(Grid) 容器。就算只建立這類格線 (Grid) 容器的其中一種,也會大幅增加建立時
間,而多次重複此格線 (Grid) 容器更會嚴重降低效能。
隨著 Flex 資料庫 (repertoire) 擴充,您會發現有許多替代的容器和控制項選擇,可
輕鬆依需要加以自訂。例如,您可使用清單 (List) 控制項和自訂儲存格轉換程式,來
產生圖 4 中的版面配置。您可將儲存格轉換程式與任何以清單為主的元件搭配使用,
以建立自訂格式儲存格,而且各儲存格可以有不同的高度。Flex 說明文件中會提供更
多資訊,並列出範例來說明如何建立自訂儲存格轉換程式。清單 (List) 控制項搭配自
訂儲存格轉換程式使用的可產生比格線 (Grid) 容器更好的效能。

ᔖᗗջ‫ޟ‬லَৠᏢ१ፒጒ‫ٽ‬

以下列出應避免的常見容器重複範例:

VBox 容器中的 <mx:Panel> 標籤 - 面板 (Panel) 容器是一種 VBox 容器,可支


援標題列、圓角邊框及其他面板 (Panel) 樣式。如果您要讓面板 (Panel) 子系的版
面配置與在 VBox 容器中的版面配置相同,請直接使用控制項填入 <mx:Panel>
標籤;不要使用 VBox 容器包住控制項。VBox 容器會變成重複的容器包裝函
式,將它移除可消除一或多層不必要的容器巢狀結構。
例如,您不要編寫如下:
<mx:Panel title="Grocery List" width="150" height="150">
<mx:VBox>
<mx:Label text="Fruits" />
<mx:Label text="Veggies" />
<mx:Label text="Cookies" />
<mx:Label text="Crackers" />
</mx:VBox>
</mx:Panel>

7
您可使用此程式碼如下:
<mx:Panel title="Grocery List" width="150" height="150">
<mx:Label text="Fruits" />
<mx:Label text="Veggies" />
<mx:Label text="Cookies" />
<mx:Label text="Crackers" />
</mx:Panel>

兩者都可產生相同的版面配置。
VBox 內部的 <mx:Application> 標籤 - 應用程式物件本身就是 VBox 版面配
置。所以不需要使用 VBox 容器來包住應用程式。將此包裝函式移除,將可消除一
或多層容器巢狀結構。
例如,您不要編寫如下:
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:VBox horizontalAlign="center" backgroundColor="#EFEFEF">
<mx:Label label="Shopping Cart" />
.
.
.
</mx:VBox>
</mx:Application>

您可使用此程式碼如下:
<mx:Application xmlns:mx=http://www.macromedia.com/2003/mxml
horizontalAlign="center" backgroundColor="#EFEFEF">
<mx:Label label="Shopping Cart" />
.
.
.
</mx:Application>

容器為 MXML 元件的最上層標籤 - MXML 元件的優點在於,它們讓您可以模組


化重複程式碼。但是,這些元件很容易發生與大型應用程式相同的效能問題。您不
需將容器標籤設為 MXML 元件定義的最上層標籤。只要將 MXML 元件當成簡單
的控制項就可以了,例如:
<mx:Image xmlns:mx=http://www.macromedia.com/2003/mxml
source="foo.jpg" width="200" height="200" />

藉由逐步執行 MXML 元件定義並刪除不必要的容器包裝函式,您就可精簡容器巢


狀結構(和許多不必要的物件),進而讓應用程式的工作量更輕鬆。
MXML 元件執行個體的容器包裝函式 - 通常,您不需使用容器來包住 MXML 元
件標籤。您可在 MXML 元件的執行個體中設定不同的樣式、標籤和 id - 而不需
使用容器來包住 MXML 元件標籤,然後在此容器中進行這些設定。例如,您不需
使用不必要的 VBox 容器來包住 MXML 元件,來設定類似以下的樣式:
<mx:VBox backgroundColor="#FFCCCC" borderStyle="solid">
<myComponent xmlns="*" />
</mx:VBox>

您可直接在 MXML 元件上設定這些樣式,例如:


<myComponent xmlns="*" backgroundColor="#FFCCCC"
borderStyle="solid" />

8
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

開發人員通常會有這種壞習慣,將不必要的容器設為 MXML 元件定義的最上層標


籤,這樣會讓每個使用的 MXML 元件至少產生兩個多餘的容器!因而產生許多未
使用的物件,將它們刪除將可大幅提升應用程式的回應速度。
重新評估您的容器選擇 - 檢視每個容器標籤,並判斷其必要性,以及是否對應用
程式的整體架構有用。是否可以使用其他版面配置管理員或版面配置樣式,來產生
相同的版面配置?修改您的版面配置,儘量讓您的應用程式變得精簡、降低整體
SWF 的輸出大小,並效能變得更加強穩。

‫ٺ‬Ң‫۽‬ᒶஈ՗এᡝϽ‫׽پ‬๡ਝ૖
如果說,效能問題的頭號原因是多餘的容器巢狀產生的不必要測量和版面配置,那麼
第二個原因就是在尚未需要之前,就先建立物件。為避免這個問題,您可以使用延遲
執行個體化。Flex 使用延遲執行個體化來判斷在應用程式啟動時,要建立哪些元件。
在使用延遲執行個體化時,您可決定使用者在哪個階段進行元件建立。容器中包含一
個 creationPolicy 屬性,您可設定它來指定 Flex 何時建立容器(在啟動時、當使
用者導覽至該容器,或根據使用者的動作)。

Ᏺ។ৠᏢԤϱ࡚‫۽‬ᒶஈ՗এᡝϽ

Flex 導覽容器(ViewStack、Accordin、TabNavigator)有內建的延遲執行個體
化。預設的延遲執行個體化操作是指 Flex 未在啟動時建立所有子系檢視,只有當使
用者導覽至該容器時才會觸發它。下列程式碼顯示兩個使用中的導覽容器
TabNavigator 和 ViewStack:
<mx:TabNavigator>
<mx:VBox id="tabNavView1">
<mx:LinkBar dataProvider="myViewStack" />
<mx:ViewStack id="myViewStack">
<mx:VBox id="view1" >
.
.
</mx:VBox>
<mx:VBox id="view2" >
.
.
</mx:VBox>
<mx:VBox id="view3" >
.
.
</mx:VBox>
</mx:ViewStack>
</mx:VBox>
<mx:VBox id="tabNavView2">
.
.
</mx:VBox>
</mx:TabNavigator>

9
TabNavigator 容器會建立 tabNavView1,因為它是當 Flex 執行個體化
TabNavigator 容器時,顯示的第一個檢視。執行個體化 tabNavView1 時,會對
LinkBar 和 ViewStack 的第一個檢視 (view1) 執行個體化。當使用者在 ViewStack
中與 LinkBar 互動,以選擇另一個檢視時,Flex 就會建立此檢視。Flex 會繼續以這
種方式,在呼叫導覽子代時才建立它們。
容器標籤上的 creationPolicy 屬性控制子系檢視的建立。下列清單說明在 Flex 導
覽容器中設定 creationPolicy 屬性時,其每個屬性的功能:
creationPolicy="auto" - 當 Flex 建立導覽容器時,並不會立即建立所有子
代,而僅會建立剛開始會出現的子代。延遲執行個體化的結果,會使具有導覽容
器的 MXML 應用程式載入的速度變快,不過當使用者從某一檢視第一次導覽至另
一檢視時,會出現短暫的停頓。可用性研究顯示,相較於讓使用者長時間等待應
用程式在啟動時建立導覽子系檢視,這種方式可提供較佳的使用者體驗。此外,
使用者也有可能永遠不會造訪其中某些子系檢視,因此在啟動時建立它們有可能
是多此一舉。
請注意,如果您在非導覽容器上設定 creationPolicy="auto",則必須加入額外
的程式碼,以指出何時要建立容器的子系。由於此額外程式碼已內建在導覽容器
中,所以您可直接在導覽容器上設定 creationPolicy="auto",而不需做額外的
工作。
creationPolicy="all" - 當 Flex 建立導覽容器時,會在所有子系檢視中建立所
有控制項。這項設定會延遲應用程式的啟動時間,但是可加速從某一檢視導覽至另
一個檢視時的回應時間。
creationPolicy="none" - Flex 會等到您明確呼叫執行個體化方法時,才會執
行個體化導覽容器中的元件或導覽容器的子系檢視。您可使用
createComponents() 方法明確執行個體化檢視。Flex 說明文件中提供有關設定
自訂元件建立計劃的詳細資訊。
運用 creationPolicy 屬性,您可手動建立子系檢視,並判斷要在應用程式架構的哪
個階段開始建立導覽容器子系檢視。可用性研究顯示,當使用 auto 設定時,可提供
較佳的使用者體驗。常見的錯誤,是在其中一個導覽容器上誤設了
creationPolicy="all",這會延遲應用程式的啟動時間。只有當您百分之百確定您
的元件建立計劃有效時,才能使用 creationPolicy="all"。

ᅚ໌Ԓ‫ގ‬७଩ည

您可以在微調效能的程序中,將應用程式的啟動時間儘可能縮到最短。但是,這不表
示您無法進一步提高效能;您可選擇使用漸進式版面配置。漸進式版面配置是一種 UI
概念,讓應用程式以逐一方式來配置元件版面,如此可縮短元件開始出現在螢幕上的
初始延遲時間。漸進式版面配置類似 HTML 應用程式連續將內容載入用戶端的方式。
漸進式版面配置雖無法量化降低應用程式的啟動時間,但卻可大幅改善使用者感受到
的啟動時間。
下列範例應用程式 ProgressiveLayoutExample.mxml 使用了漸進式版面配置。當
您執行應用程式時,您會看到應用程式以骨牌式檢視畫面,改善使用者感受到的啟動
時間。(您可從 Macromedia 網站下載此應用程式,網址為:
http://download.macromedia.com/pub/developer/solution_samples.zip。此應
用程式為範例檔案 (Sample Files) 下載檔的一部份下載。)

10
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

ProgressiveLayoutExample.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
creationComplete="createLater()">
<mx:Script>
<![CDATA[

var creationOrder = ["panel1", "panel2", "panel3"];


var creationIndex = 0;

function createNext(){
var nextObj = this[creationOrder[creationIndex++]];
nextObj.createComponents();
if(creationIndex < creationOrder.length){

nextObj.getChildAt(0).addEventListener("creationComplete",
mx.utils.Delegate.create(this, createLater));
}
}

function createLater(e:Object):Void{
doLater(this, "createNext");
}
]]>
</mx:Script>

<mx:HBox>

<mx:Panel id="panel1" title="Panel 1" width="210" height="240"


horizontalAlign="center" verticalAlign="middle"
creationPolicy="none">
<mx:DataGrid width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:Object Artist="Death Cab for Cutie" />
<mx:Object Artist="The Postal Service" />
</mx:Array>
</mx:dataProvider>
</mx:DataGrid>
<mx:DataGrid width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:Object Album="Such Great Heights" />
<mx:Object Album="We Know the Facts" />
</mx:Array>
</mx:dataProvider>
</mx:DataGrid>
</mx:Panel>

<mx:Panel id="panel2" title="Panel 2" width="210" height="240"


horizontalAlign="center" verticalAlign="middle"
creationPolicy="none">
<mx:List width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:String>one</mx:String>
<mx:String>two</mx:String>
<mx:String>three</mx:String>
<mx:String>four</mx:String>
</mx:Array>

11
</mx:dataProvider>
</mx:List>
<mx:List width="190" height="95">
<mx:dataProvider>
<mx:Array>
<mx:String>red</mx:String>
<mx:String>green</mx:String>
<mx:String>yellow</mx:String>
<mx:String>blue</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:List>
</mx:Panel>
<mx:Panel id="panel3" title="Panel 3" width="210" height="240"
horizontalAlign="center" verticalAlign="middle"
creationPolicy="none">
<mx:Tree width="190" height="95">
<mx:dataProvider>
<mx:XML>
<node label="File">
<node label="Open"/>
</node>
<node label="Close">
<node label="Help"/>
</node>
</mx:XML>
</mx:dataProvider>
</mx:Tree>
<mx:TextArea width="190" height="95">
<mx:text>The Macromedia Flex presentation server
offers a familiar, standards-based programming framework and
powerful set of components for creating a rich, responsive
presentation tier for enterprise Rich Internet Applications
(RIAs).</mx:text>
</mx:TextArea>
</mx:Panel>
</mx:HBox>

</mx:Application>

您可使用下列步驟,在您自己的 Flex 應用程式中建立漸進式版面配置。您可以參考


ProgressiveLayoutExample.mxml 範例應用程式。
1 指出您要顯示應用程式的順序。也就是,指出後,再排列您要顯示最上層容器的順
序,並排列這些容器子系的順序。您可以依您喜歡的順序來配置應用程式版面,從
上到或、從左到右等等。
2 在 creationOrder 方法中,指定您的版面配置順序。
3 在您已加入 creationOrder 方法的容器上,將 creationPolicy 屬性設為
none。如此可避免讓 Flex 在啟動時建立容器的子系。

4 為 creationOrder 方法中指定的容器設定明確的寬度和高度值。如此,應用程式
就可判斷該容器的大小,而不需等容器填入子系時,再計算它的大小。如果您略過
此步驟,則會看到容器以預設的寬度和高度出現,然後當 Flex 建立子系時,再變
大以容納它們。這種重新調整大小的作業會耗用大量資源,而且不美觀。
您可先執行應用程式而不加入漸進式版面配置程式碼,以解譯容器的寬度和高度。
您可將容器的寬度和高度與兩個暫時標籤繫結。而繫結至標籤的寬度和高度為容器
的偏好大小,當您加入漸進式版面配置程式碼時,它們就是您設定的硬式編碼寬度
與高度值。下列程式碼片段說明如何解譯 HBox 容器的計算寬度和高度:

12
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

<mx:HBox id="firstBox">
..controls..
..controls..
</mx:HBox>
<mx:Label id="debug1" text="{firstBox.width}" />
<mx:Label id="debug2" text="{firstBox.height}" />

5 剪下並貼上在 <mx:Script> 區塊中的指令碼。在觸發後,此程式碼會重複


creationOrder 方法,來建立每個容器及其子系。我們簡短地解釋 doLater() 呼
叫。
6 在 <mx:Application> 標籤上加入主要的 creationComplete 處理常式,以觸發
建立 creationOrder 方法中的第一個項目。
進行幾項調校後,您就可在應用程式中加入漸進式版面配置,在啟動時先顯示繫結至
資料服務傳回資料的檢視,如下列範例應用程式中所示。(您可從 Macromedia 網
站下載此應用程式,網址為:
http://download.macromedia.com/pub/developer/solution_samples.zip。此應
用程式為範例檔案 (Sample Files) 下載檔的一部份下載。)
DataService_ProgressLayoutExample.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
creationComplete="createLater()">
<mx:Script>
<![CDATA[

var creationOrder:Array;

function addToCreationOrderQueue(container, dataProvider)


{
container.dataProvider = dataProvider;
if (creationOrder.length == 0)
createLater();
creationOrder.push(container);
}

function createNext(){
var nextObj = creationOrder.shift();
nextObj.createComponents();
if (creationOrder.length > 0) {

nextObj.getChildAt(0).addEventListener("creationComplete",
mx.utils.Delegate.create(this, createLater));
}
}

13
function createLater(e:Object):Void{
doLater(this, "createNext");
}

]]>
</mx:Script>

<!-- Data Service Definitions -->


<mx:WebService id="webService1"
wsdl="http://somewhere.com/my.wsdl">
<mx:operation name="getNames"
result="addToCreationOrderQueue(panel1, getNames.result);">
..
..
..
</mx:operation>
</mx:WebService>
<mx:WebService id="webService2"
wsdl="http://somewhere.com/foo.wsdl">
<mx:operation name="getBios"
result="addToCreationOrderQueue(panel2, getBios.result);">
..
..
..
</mx:operation>
</mx:WebService>

<mx:HTTPService id="serviceObject"
url="http://somesite.com/directory/myfile.xml" method="POST"
fault="alert(event.fault.faultstring);"
result="addToCreationOrderQueue(panel1,
serviceObject.companyDetailInfo);" resultFormat="object">
<mx:request>
<arg1>value1</arg1>
<arg2>value2</arg2>
</mx:request>
</mx:HTTPService>

<!-- Views -->


<mx:HBox>

14
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

<mx:Panel id="panel1" title="Panel 1" width="210" height="240">


<!--CONTROLS IN THIS PANEL USE DATA FROM serviceObject -->
...
...
...
</mx:Panel>

<mx:Panel id="panel2" title="Panel 2" width="210" height="240">


<!-- CONTROLS IN THIS PANEL USE DATA FROM webService1 -->
...
...
...
</mx:Panel>

<mx:Panel id="panel3" title="Panel 3" width="210" height="240">


<!-- CONTROLS IN THIS PANEL USE DATA FROM webService2 -->
...
...
...
</mx:Panel>

</mx:HBox>

</mx:Application>

此範例應用程式使用漸進式版面配置,每個檢視都相依於資料服務傳入的資料。它會
使用來自不同資料服務傳回的資料填入子系,載入三個面板。您要確定只有當資料服
務已傳回其產生的資料時,才建立這三個面板。若要這麼做,您必須修改建立時機,
如此才能僅當對應的資料服務傳回結果時,才會使用物件填入 creationOrder 佇
列。您可使用資料服務的結果處理常式來進行這項工作,步驟如下:
1 在呼叫 addToCreationOrderQueue() 方法的資料服務標籤上,定義結果處理常
式。當對應資料傳回並可用來填入控制項時,此方法會將容器 id 加入
creationOrder 方法中。此方法的第二個參數 dataProvider 屬性,則為資料服
務傳回的資料。本步驟預設程式碼已在別處編寫好,以解析資料並準備將資料與
控制項繫結。
2 將 creationComplete="createLater()" 程式碼加入 <mx:Application> 標
籤。如此會觸發當該檢視的資料傳回時,建立第一個檢視。
3 複製程式碼至 <mx:Script> 區塊。此程式碼會處理將檢視加入 creationOrder
佇列的工作,並當其相依的資料傳回時,就開始建立檢視。

15
依這些步驟進行可保證只在檢視的資料可用時,才會建立該檢視。但是,上述程式碼
僅適用於 DataService_ProgressiveLayoutExample.mxml 專用的特定模組和檢
視。在加入漸進式展現(尤其當有相依資料時才建立檢視)時,通常需要視個別應用
程式來修改程式碼。

‫۽‬ᒶଢ଼հ

您可使用 Flex doLater() 方法來延遲動作。doLater() 方法具備下列函數簽章:


doLater(obj:Object, func: String, args: Array):Void

此方法會在目前呼叫的函數執行完成後,執行函數(第二個引數)。在本文稍早的
「漸進式佈局」一節所討論的漸進式版面配置範例應用程式
(ProgressiveLayoutExample.mxml) 中,您可看到使用 doLater() 方法的範例。
在該程式碼中,當剛建立的物件在繪製中時,creationComplete 事件就會執行。請
先等剛建立的物件繪製完成後,再開始建立下個物件。使用 doLater() 方法來完成
此延遲。簡單地說,creationComplete 事件處理常式會呼叫 doLater() 方法,而
不會馬上建立並繪製下個物件。

೎౩σ໔‫ޟ‬ၥਟ໱
有時您應用程式的速度會變慢,因為它正同時在管理大量的資料。Flex 團隊軟體工程
師 Matt Chotin 針對資料管理提出一些很好的建議,來處理這個問題他在他的 blog
中,討論如何整合分頁、排序及改善感受到的效能,網址為:
www.markme.com/mchotin/archives/cat_data_management.cfm。

໷ᄱӴኬܹፒӫ੫ਝ
您可能會注意到轉場特效有點不順暢,尤其當您將時間較短的特效套用在大型檢視上
時。不順暢的定義是什麼?例如,淡化 (Fade) 特效會明顯地以數個 alpha 階段分次
淡化,而不會流暢平順地淡化。或是縮效 (Zoom) 特效會明顯地以數個大小分次縮
放,而不會逐漸流暢地縮放。有幾個方式可調整個的轉場特效,使播放至順暢。請嘗
試下列建議組合,以找出最能改善您應用程式特效的方法。

使用時間長度屬性來提高特效的時間長度。如此可將明顯而不順暢的階段延伸為
較長的時間,讓肉眼填滿差異,或在觀看時感覺特效比較順暢。真的會產生不一
樣的效果。
在動畫中,Flash Player 越不需要重複繪製,特效在播放時就越順暢。如要這麼
做,讓目標檢視的一部份在特效開始時隱形,然後播放特效,等特效完成後,再顯
示那些部份。由於填入控制項的程序很快,所以肉眼不會察覺到任何延遲或控制項
突然出現。其編碼很簡單:進入 effectStart 和 effectEnd 事件,以控制在特效
前後要顯示的部份。這項技巧僅適用於當特效的時間長度較短時(500 微秒或更
短),且僅適用於 showEffect 或 hideEffect 事件。在其他情況下,隱藏物件
的部份看起來就不是那麼流暢了。

16
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

避免使用以點陣圖 (bitmap) 為主的背景。設計人員通常會使用單色、漸層、淡花


紋等等的背景影像。為減輕 Flash Player 重複繪製的負擔,請儘量將背景影像改
為單色的背景。或者,如果您想使用淡漸層而不使用單色,請使用 SWF 或 SVG
格式的背景影像檔。Flash Player 在進行重繪時,使用這兩種格式會比使用標準
JPG 或 PNG 檔來得輕鬆。
有時動畫播放不流暢,是因為需要進行背景處理而干擾了動畫的播放。當您在根據
web-service 結果填入控制項的處理常式中附加了特效,或在建立大型檢視時加上特
效時,可能就會出現這種情況。特效(Effect) 類別(淡化 (Fade)、移動 (Move)、
調整大小 (Resize)、WipeLeft 等等)的子類別標籤集有一個公用屬性:
suspendBackgroundProcessing。當它設為 true 時,就會在特效播放時,封鎖所有
背景處理,例如測量及版面配置。預設值為 false。建議您將此屬性設為 true,讓
特效播放更流暢。但是,請注意,當您啟動 suspendBackgroundProcessing 時,一
旦特效播放後,就無法中斷。因此,有時您應避免使用
suspendBackgroundProcessing="true"。常見的特效使用,是在應用程式在等待
web-service 結果傳回時,播放特效。當 web-service 結果傳回時,結果處理常式會
嘗試中斷特效。如果 suspendBackgroundProcessing 設為 true,則結果處理常式
就無法中斷特效,而特效會繼續播放,使應用程式懸滯。在這類情況下,應避免使用
suspendBackgroundProcessing。

‫ٺ‬Ңஈ՗ਢ෈ኺԒႀԙ‫ޟٹ؁‬ਝ૖
執行時期階層式樣式的功能十分強大,但您應謹慎使用,並在適當的情況下使用。在
物件的執行個體上動態設定樣式意味著存取 UIObject 的 setStyle() 方法。在 Flex
應用程式模組架構中,呼叫 setStyle() 方法是最耗用資源的作業,因為此呼叫需要
通知所有剛建立樣式的物件的子系,去執行另一個樣式查閱作業。而必需通知的結果
子系樹狀結構可能會變得很大。
影響效能的常見錯誤,就是濫用或非必要地使用 setStyle() 方法通常,只有當您要
改變現有物件的樣式時,才需要用到 setStyle()。當您第一次設定物件樣式時,請
勿使用它。您可透過外部 CSS 樣式表或全域樣式,在 <mx:Style> 區塊中設定樣
式,做為 MXML 標籤上的明確樣式屬性。如果當程式執行(不論是您的應用程式、
導覽中的新檢視或動態建立的元件)時,您希望這些樣式不會改變,則必須使用正確
的樣式資訊來初始化物件(不論是您的應用程式、導覽中的新檢視或動態建立的元件)。
有些應用程式需要在應用程式或物件執行個體化時,呼叫 setStyle() 方法。此時,
則需要在執行個體化階段之前,先呼叫 setStyle() 方法,以避免非必要的查詢。在
執行個體化階段之前是指,在元件或應用程式的 initialize 事件(而不是在
creationComplete 或其他事件)中設定樣式。在初始時儘早設定樣式,您就可避免
非必要的樣式通知和查詢。

17
‫׽‬๡ Repeater ‫ސ‬Ӈ‫ޟ‬ਝ૖
如有需要加速 Repeater 物件的效能,有幾個事項必須注意。首先,若將容器當作
Repeater 物件的子項使用,請確定容器沒有不必要的容器巢狀結構,而且愈簡潔愈
好。如果重複檢視的單一執行個體就要花上一段時間來產生,那麼重複的動作會更惡
化這種情形。如本文前面所述,多個 Grid 容器在 Repeater 物件中重複並不會獲得
良好的效能,原因是 Grid 容器本身就是需要耗費大量資源才能產生的容器。另一個
解決方法是使用 List 控制項加上自訂的儲存格轉換程式。
您也應將 recycleChildren 屬性設為 true 來改善 Repeater 物件的效能。
recycleChildren 屬性是一個布林 (Boolean) 值,當設為 true 時,會將新的資料項
目繫結到現有的 Repeater 子項,而有更多的資料項目時會逐漸建立新的子項,同時
摧毀不再需要的多餘子項。
當您將此屬性設為 false 時,如交換 dataProvider 屬性、執行排序等動作,
Repeater 物件就會重新建立所有重複的物件,因而造成效能延遲。以 FlexStore 為
例,存取網址為:
www.macromedia.com/flex/samples/flexstore/flexstore.mxml?versionCheck
ed=true,便使用了 recycleChildren。當您載入應用程式時,請注意產品縮圖檢視
下方的 Sort by(排序依據)選項。此選項可讓使用者依名稱或價格排序產品縮圖。
其實改變的並不是縮圖檢視,而是 Repeater object 物件的 dataProvider 屬性順
序。將 recycleChildren 屬性設為 true,Repeater 物件不會重新建立每個縮圖檢
視,而只是依據名稱或價格重新排列 dataProvider 屬性的順序。
recycleChildren 屬性的預設值是 false,這麼做可確保您不會將過期的狀態資訊
留在重複的執行個體中。舉例來說,假設您使用 Repeater 物件來顯示照片影像,而
每個 Image 控制項又有關聯的 NumericStepper 控制項來輸入訂購的份數。像是影
像等部份狀態資訊是來自 dataProvider 屬性,而其他狀態資訊,例如份數計算,則
是由使用者互動設定。如果您將 recycleChildren 屬性設為 true,然後遞增
Repeater 物件的 startingIndex 值來依頁排列照片,Image 控制項是會繫結到新
的影像,但 NumericStepper 控制項卻仍然還會是舊的資訊!只有在手動重設狀態資
訊太麻煩,或是確定修改 dataProvider 應不會觸發 Repeater 物件的子項重新建立
時,才應使用 recycleChildren="false"。
雖然這樣說有點多此一舉,但當 Repeater 物件第一次載入時,recycleChildren 屬
性對 Repeater 物件的速度並沒有影響。recycleChildren 屬性只會改善後續
Repeater 個體的效能。如果您確定 Repeater 物件只建立子項一次,就不需要使用
recycleChildren 屬性,也無須擔心過期的狀態資訊。

18
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

ᕣ၌ Flex ৤Ұթ݈Ꮲϛ‫ڥפޟ‬ђ૖
Flex 使用記憶體內快取來處理 MXML 網頁的請求。當第一次叫用 MXML 網頁時,
編譯器會建立 SWF 檔案,並將檔案儲存在 Flex 快取中。Flex 也會建立並快取
HTML 封套 (Wrapper) 網頁,並從此快取處理後續的網頁請求。圖 5 顯示整個流程。

ყ 5Ȉ! MXML 網頁的快取請求

Flex 也會快取附屬檔案,例如 SWC、MXML 及 ActionScript 檔案。Flex 會參照


所有附屬檔案,例如 CSS 樣式表、<mx:Image> 標籤中使用的影像以及
<mx:Script> 標籤內含的 ActionScript 檔案,並將這些檔案儲存在 /WEB-
INF/flex/cache.dep 檔案中。如附屬檔案有變更,Flex 便會重新編譯 MXML 檔案。
Flex 快取設定是在 flex-config.xml 組態檔的 <cache>...</cache> 區段中設定
的。Flex 利用 <cache-mxml>true</cache-mxml> 項目,預設啟用快取。如果您將
此項目設為 false,對 MXML 檔案的所有請求就會強制重新編譯 MXML 文件。
flex-config.xml 檔案中的 <content-size>500</content-size> 項目會定義快取的
預設大小上限,也就是 500 個項目。內容值的大小不是按 MXML 檔案的總數定義,
而是快取的項目總數。舉例來說,單一 MXML 檔案會在快取中寫入兩個項目:一個
是 HTML shell,另一則是 SWF 檔案。在多數情況下,預設 500 個項目就夠了,但
若為大型企業應用程式,可能會有不少 MXML 文件。Flex 會針對不同的 URL 配對
(例如 page.mxml?accessible=true)建立額外的快取項目。在 URL 中設定
accessible=true,可建立新的唯一 SWF 檔案及 HTML shell,並加入到快取中。
增加此值並不會耗費太多記憶體,因為多數 HTML shell 都只有幾個 KB 大小,而大
部分的 Flex SWF 檔案都在 100 到 150K 上下。
當您使用 JSP 標籤庫將 MXML 嵌入 JSP 或 CFM 網頁,Flex 會使用另外的快取儲
存 MXML 程式碼片段。Flex 用 <mxml-size> 項目定義此快取,預設值為 500。以
下範例顯示一 JSP 網頁的程式碼片段:
<mx:Application>
<mx:Label text="Hello"/>
</mx:Application>

19
此程式碼片段會快取在 <mxml-size> 項目所定義的來源快取中。編譯來源所產生的
SWF 檔案及 HTML shell 將快取在 <content-size> 快取設定所定義的內容快取
中。若網頁中的來源片段有所變更,新的快取項目會加入來源快取中,而 Flex 會編
譯新的 SWF 檔案。
<mm:mxml>
<mx:Application>
<mx:Label text="Hello"/>
</mx:Application>
</mm:mxml>

當 Flex 達到快取的大小上限,便會刪除最早使用的檔案。Flex 1.0 無法查看快取中


有多少項目,而伺服器執行時也無法清除快取。您在下一節會看到,其實只有伺服器
在設定 production-mode=true 的情況下執行才會發生這個問題。在開發期間,檔
案監控程式 (File Watcher) 將監視在 /WEB-INF/flex/cache.dep 中定義的所有附
屬檔案;如有檔案變更,Flex 就會重新編譯相對應的 MXML 檔案並重新整理快取。
如需 Flex 實作快取的詳細資訊,請參閱開發 Flex 應用程式說明文件中的
「Configuring Caching」(設定快取)一節,網址為:
http://livedocs.macromedia.com/flex/1/flex_docs/36_admi5.htm#wp121792

ও‫ ׽‬flex-config.xml ಢᄘ೩ۡ
要改善實際執行環境的效能,最簡單的方法就是將 flex-config.xml 檔案中的
production-mode 屬性設為 true。這會在 Flex 中產生幾項效果。

停用 flex-config.xml 中 <debugging> 區塊所設定的全部除錯與測試分析


(Profiling) 功能。
另外也會強制 Flex 忽略查詢字串參數覆寫,例如 ?debug=true
及 ?asprofile=true。
若您啟用實際執行模式,當伺服器啟動時,Flex 只會檢查變更的檔案。Flex 不會使
用 <file-watcher-interval> 設定來連續輪詢檔案。您必須重新啟動應用程式或
J2EE 伺服器執行個體,才能在實際執行時更新 MXML 或附屬檔案。
可改善效能的另一個組態設定是 flex-config.xml 檔案中 <compiler> 區段的
<optimize> 屬性。<optimize> 屬性預設為 true。藉由將 <optimize> 設為
true,ActionScript 最佳化程式可將產生的 SWF 檔案大小減少 10 到 15%。最佳
化程式會在編譯之前變更產生的 ActionScipt 程式碼。這可減少編譯時間,並改善
Flash Player 的執行期效能。在開發期間,如果您使用追蹤陳述式,應將
<optimize> 設為 false,以免編譯器將追蹤陳述式移除。

20
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

Ԇ‫ ڥ‬Flex ၥਟ݈୛
您如何存取 Flex 應用程式中的資料,將對效能造成影響。由於應用程式在第一次要
求後會快取在瀏覽器上,因此資料存取會在應用程式執行時大幅影響效能。Flex 提供
幾種方法來將資料傳送到用戶端。它透過執行期服務來傳送資料,這些服務會叫用已
載入 Flex 類別路徑 (classpath) 的 Java 類別,或是將 proxy 要求傳送到網頁服務
或 HTTP 伺服器。圖 6 顯示可用的 Flex 資料服務。

ყ 6Ȉ! Flex 資料服務

以下清單針對 Flex 資料服務逐一說明:

網頁服務 proxy — 由於 Flash Player 有安全沙盒 (sandbox) 機制,對網頁服務


的要求只能傳送到載入 SWF 檔案的同樣網域。在許多情況下,網頁服務會位於其
他網域。在 Flex 中,所有網頁服務要求都經由在 Flex 展示伺服器上執行的網頁
服務 proxy 傳送。下面這一段程式碼顯示如何呼叫網頁服務。
<mx:WebService id="ws" wsdl="http://acme.com/stock.wsdl">
<mx:operation name="getQuote"/>
</mx:WebService>

當 SWF 檔案載入用戶端時,會傳送要求到網頁服務 proxy,要求 WSDL 檔案。


接著,網頁服務 proxy 會要求 WSDL 檔案,並將回應傳回用戶端,用 proxy 將
回應傳回原始用戶端。使用 <mx:Webservice> 標籤的所有用戶端伺服器互動都會
經由 proxy 傳遞,除非使用 useProxy="false" 屬性。當您使用 useProxy="false"
時,Flash 用戶端會將網頁服務呼叫直接傳送到終端服務。使用此一屬性的同時又
要讓 Flash 用戶端的沙盒機制發揮作用,終端服務必須有 crossdomain.xml 檔
案。在某些情況下,終端服務並非您所能控制,這時就需要 proxy。
遠端物件 proxy — 遠端物件 proxy 可讓您存取在 Flex 展示伺服器上執行的伺服
器端物件(Java Beans、EJB、POJOS)。遠端物件 proxy 使用兩種不同編碼
機制,您可以修改 RemoteObject 標籤當中的編碼屬性來選擇其一。預設的編碼機
制為 AMF (動作訊息格式,Action Message Format),這是一種二進位通訊
協定,用於伺服器與用戶端之間的資料傳輸。遠端物件 proxy 也可將資料編碼成
標準的 SOAP 封包。下面程式碼顯示如何在 RemoteObject 標籤使用 AMF 和
SOAP:
<mx:RemoteObject id="ro" src="samples.StockBean" encoding="AMF">
<mx:method name="getQuote">
</mx:method>

21
</mx:RemoteObject>
<mx:RemoteObject id="ro" src="samples.StockBean" encoding="SOAP">
<mx:method name="getQuote">
</mx:method>
</mx:RemoteObject>

HTTP 服務 — 這是第三種資料存取方法,使用 HTTPService 標籤加上遠端 URL


來將 XML 載入 Flash Player。HTTP 服務 proxy 會處理來自 Flash 用戶端的要
求,proxy 接著再叫用 URL,並將回應轉回使用 proxy 的用戶端。下面這一段程
式碼顯示如何使用 HTTPService 標籤:
<mx:HTTPService id="myRequest" url=http://acme.com/mydata.xml>
</mx:HTTPService>

您可以使用遵循標準的方法來從 Flex 應用程式存取資料,但在某些情況下,您可利


用其他選項來改善效能。使用 <mx:Webservice> 及 <mx:RemoteObject> 標籤加上
encoding="SOAP",可讓您使用遵循標準的方法,但卻不一定會產生最佳的效能。此
外,與 AMF 相較,SOAP 編碼使用較多的 XML,也會額外產生一些負荷。一般來
說,AMF 要比 SOAP 快上三倍,而在負載極大的情況下,可快上六倍之多。這是因
為 AMF 使用二進位通訊協定,與使用 XML 的 soap 封包相較,在資料相同的情況
下,可大幅減少負載大小。SOAP 搭配網頁服務的效能也需視網頁服務實作而定。不
同應用程式伺服器在後端使用不同的網頁服務,因此視實作而定,可能會有效能上的
差異。要瞭解實作的效能,唯一的方法就是用負載測試來測試服務。以相同的資料而
言,SOAP 的大小通常是 AMF 的兩倍。藉由使用 AMF,您可減少應用程式的整體
頻寬使用量。
將資料傳送的效能提至最高的兩種方法就是 XML 使用 HTTPService 或
RemoteObject 搭配 AMF。如前所述,網頁服務可能會因為在伺服器和用戶端上進
行 SOAP 封包序列化和去序列化而變慢。在許多情況下,要使用哪一種方法將視您現
有的應用程式,以及選擇如何整合後端伺服器端資源而定。網頁服務的效能有很大部
分可能會受到應用程式伺服器的網頁服務引擎基本實作影響,因此您應該使用負載測
試來確認其效能。
您也可以選擇不透過 Flex 中的資料服務,而直接叫用服務。如果您嘗試叫用的服務
位於 MXML 及 SWF 檔案所在位置相同的主機上,或有同樣的網域名稱,您可以加
入 useProxy="false" 屬性來直接叫用服務。當您指定 useProxy="false" 時,
Flash 用戶端就不再透過 Flex proxy 傳送呼叫,而直接將呼叫傳送到終端服務。如
果 MXML 文件和服務是從不同網域或主機提供,您必須將 crossdomain.xml 檔案
放在服務所在的伺服器上。如需此程序的詳細資訊,請參閱 Flash 7 安全說明文件,
網址為:
www.macromedia.com/devnet/mx/flash/articles/fplayer_security_03.html。
Macromedia 建議您使用 proxy 來進行開發,因為 proxy 可協助您除錯,而且也請
只有在確定效能於實際執行時需要 proxy 的情況下,才關閉 proxy。

22
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

‫ٺ‬Ң JSP ኿ᡆ৲


Flex 提供 JSP 標籤庫,可讓您將 MXML 直接整合到 JSP 或 ColdFusion 網頁。標
籤庫可讓開發人員建立混合式應用程式,將 HTML 及 Flex 應用程式同時整合到網頁
中。舉例來說,如果您有一個 HTML 應用程式,想慢慢地將豐富使用者介面導入到
該應用程式中,您就可以運用標籤庫,迅速輕鬆地將其加入到您的應用程式中。將股
票行情加入到 HTML 應用程式就是很明顯的例子之一。如果用 HTML 張貼,使用者
就必須重新整理整個網頁來查詢某一支股票的行情。但藉由加入豐富使用者介面,使
用者不必重新整理整個網頁就可以看到結果。
不過,若使用不當,標籤庫可能會不斷強制編譯,造成效能嚴重低落。下面這一段程
式碼顯示如何使用 Flex 標籤庫。在此例中,Flex 將編譯 MXML 檔案,並將 SWF
檔案儲存到快取中。只要 MXML 程式碼不變,Flex 就會持續使用快取中的內容檔案。
<%@ taglib uri="FlexTagLib" prefix="mm" %>
<mm:mxml>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
width="200" height="200">
<mx:Label id="label0" text="Hello World "/>
</mx:Application>
</mm:mxml>

若 Flex 程式碼不斷更動,如下面的範例所示,那麼 MXML 內容只要一有變更,


Flex 就會編譯新版本。在此情況下,針對透過應用程式登入的個別使用者,應用程式
會設定新的 session.username 值。這會導致 MXML 內容改變,也會讓 Flex 快取
另外版本的程式碼及 SWF 內容。
<%@ taglib uri="FlexTagLib" prefix="mm" %>
<% session.setAttribute("username", "brandon"); %>
<mm:mxml>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
width="200" height="200">
<mx:Label id="label0" text="Hi <%=
session.getAttribute("username") %> "/>
</mx:Application>
</mm:mxml>

由於會不斷進行編譯,因此這並不是一個很好的方法。舉例來說,如果有 500 位個
別使用者同時存取此應用程式,session.username 的值就會有 500 個不同的值,
而導致另外 499 次的 MXML 編譯。這也會在快取中增加不少的項目。比較好的做法
是使用 Flex 標籤庫的 <param> 標籤,將變數傳遞到 Flex 應用程式。只要在 MXML
script 區塊中宣告變數,接著就可以使用該變數的值。下面的程式碼顯示了最佳的做
法,來解決前面程式碼所遇到的問題。如此一來,網頁只要編譯一次,而每次有個別
使用者存取應用程式時,應用程式便會透過 mm:param 值傳遞個別使用者名稱。
<% session.setAttribute("username", "brandon"); %>
<%@ taglib uri="FlexTagLib" prefix="mm" %>
<mm:mxml>
<mm:param name="userName" value="<%=
session.getAttribute("username") %>" />
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
width="200" height="200">
<mx:Script>
var userName:String;
</mx:Script>
<mx:Label id="uName" text="Hi {userName}"/>
</mx:Application>
</mm:mxml>

23
<param> 標籤可以用來傳遞簡單的值,但若要將 XML 樹狀結構或複雜物件傳到 Flex
應用程式時又該怎辦?下面範例顯示如何使用標籤庫,將 XML 傳遞到 MXML 文
件。做法有兩種,而哪種的效能較佳,要視 XML 為靜態或動態而定。若 XML 為靜
態,那麼將 JSP 程式碼嵌入 MXML 文件,會有較佳的效能,如下面範例所示:
<%@ taglib uri="FlexTagLib" prefix="mm" %>
<html>
<%
String tree="<node label='Option 1'><node label='Option
1.1'/><node label='Option 1.2'/></node><node label='Option
2'/>"; %>
<mm:mxml>
<mx:Application width="250" height="250"
xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:XML id="myTree">
<%= tree %>
</mx:XML>
<mx:Tree dataProvider="{myTree}"/>
</mx:Application>
</mm:mxml>
</html>

如 XML 為動態,那麼 XML 一有變更,Flex 就需要重新編譯 MXML,導致效能低


落。在處理動態資料時,最好是用 <mx:HttpService> 項目,將 XML 動態地從伺服
器載入提供 XML 的 JSP 或 servlet。下面程式碼將叫用 JSP,此 JSP 會在初始化
時將 XML 送回 Flex 應用程式。在 XML 傳回後,Flex 便會將結果直接繫結到
<mx:Tree> 控制項。
<%@ taglib uri="FlexTagLib" prefix="mm" %>
<html>
<mm:mxml>
<mx:Application width="250" height="250"
xmlns:mx="http://www.macromedia.com/2003/mxml"
initialize="xmlFeed.send()">
<mx:HTTPService id="xmlFeed"
url="@ContextRoot()/perfpaper/xmlfeed.jsp"
resultFormat="xml"/>
<mx:Tree dataProvider="{xmlFeed.result}"/>
</mx:Application>
</mm:mxml>
</html>

Flex JSP 標籤庫提供開發人員一組強大的功能,可將 MXML 嵌入現有應用程式並建


立混合式 Rich Internet Applications (RIA)。如果使用正確,運作也正常,就只要
記得動態 MXML 會導致重新編譯,而且可能會迅速填滿快取。如需使用 JSP 標籤庫
的完整詳細資訊,請參閱 Flex 說明文件,網址為:
http://livedocs.macromedia.com/flex/1/flex_docs/35_jsps.htm#wp121778。

Ⴑӑጡឍ MXML ᆩॲ
前面有關快取的章節討論了為求最佳效能,您必須重新編譯 MXML 檔案,並在伺服
器重新啟動後將檔案載入到快取。另一個選擇是用遠端編譯器 mxmlc 預先編譯
MXML 網頁,然後建立自己的 HTML shell 來將 SWF 檔案載入瀏覽器。這可讓您
部署位元程式碼 (bytecode),但工作不僅僅只有讓 Flex 即時為您建立 HTML 封套。
由於像播放程式偵測及歷史管理等許多功能都不再自動產生,您必須將這些編碼到
HTML 封套中才能提供這些功能。

24
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

下面程式碼顯示如何預先編譯 MXML 檔案,以建立 HTML 封套。程式碼中有個


TabNavigator 容器並附四個標籤。如果您將這一段程式碼放入 MXML 檔案,並透
過瀏覽器加以叫用,您就可以點選標籤,並使用瀏覽器的「上一頁」及「下一頁」按
鈕來在 Flex 應用程式中來回移動。
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Panel title="My Application">
<mx:TabNavigator borderStyle="solid">
<mx:VBox label="Pane1" width="300" height="150" >
<mx:TextArea text="Hello World" />
</mx:VBox>
<mx:VBox label="Pane2" width="300" height="150" >
</mx:VBox>
<mx:VBox label="Pane3" width="300" height="150" >
</mx:VBox>
<mx:VBox label="Pane4" width="300" height="150" >
</mx:VBox>
</mx:TabNavigator>
</mx:Panel>
</mx:Application>

若要避免此檔案在伺服器每次重新啟動時編譯,您可使用 mxmlc 預先編譯檔案,如


下所示:
{flex-root}bin\mxmlc ..\jrun4\servers\default\flex\TabNav.mxml

如需使用 mxmlc 的完整詳細資訊,請參閱 Flex 說明文件,網址為:


http://livedocs.macromedia.com/flex/1/flex_docs/ 36_admi2.htm -
wp121781。
注意:請詳讀 Flex 使用者授權合約,瞭解如何散佈使用 mxmlc 所建立的 SWL 檔
案。另外也請注意,如使用 Flex 試用及開發版,用 mxmlc 建立的所有 SWF 檔案
將在編譯後一天過期。若為 Flex 完整版,則這些檔案不會過期。
在下面的範例中,mxmlc 會在與 MXML 相同的目錄中建立 SWF 檔案。下一步是建
立 HTML shell,並將 SWF 檔案整合到 HTML、JSP 或 CFM 檔案,或是 servlet
中。最簡單的方法是使用 shell,其由相同 Flex 應用程式內的 MXML 檔案產生。藉
由使用 Flex 產生的 shell,您便能保有 Flex 歷史管理功能。您只需要在四個位置
中,將 file.mxml.swf 項目換成 file.swf 項目即可。例如:
<script language='javascript' charset='utf-8' src='/flex/flex-
internal?action=js'></script>
<noscript>
<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'
codebase='http://download.macromedia.com/pub/shockwave/cabs/fl
ash/swflash.cab#version=7,0,14,0' width='100%' height='100%'
>
<param name='flashVars' value=''>
<param name='src' value='TabNav.swf'>
<embed pluginspage='http://www.macromedia.com/go/getflashplayer'
width='100%' height='100%' flashVars='' src='TabNav.swf'
/>
</object>
</noscript>
<script language='javascript' charset='utf-8'>
document.write("<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-
444553540000'
codebase='http://download.macromedia.com/pub/shockwave/cabs/fl
ash/swflash.cab#version=7,0,14,0' width='100%' height='100%'");
document.write(">");

25
document.write(" <param name='flashVars'
value='historyUrl=%2Fflex%2Fflex%2Dinternal%2Fhistory%2Fhistor
y%2Ehtml&lconid=" + lc_id +"'>");
document.write(" <param name='src' value='TabNav.swf'>");
document.write(" <embed
pluginspage='http://www.macromedia.com/go/getflashplayer'
width='100%' height='100%'");
document.write("
flashVars='historyUrl=%2Fflex%2Fflex%2Dinternal%2Fhistory%2Fhi
story%2Ehtml&lconid=" + lc_id +"'");
document.write(" src='TabNav.swf'");
document.write(" />");
document.write("</object>");
</script>
<script language='javascript' charset='utf-8'>
document.write("<br><iframe src='/flex/flex-
internal/history/history.html' name='_history' frameborder='0'
scrolling='no' width='22' height='0'></iframe></br>");
</script>

歷史管理要能運作,您必須確定應用程式的內容根目錄 (context-root) 是正確的。如


果您部署內容根目錄為 /flex 的 Flex,就必須在 HTML 封套中所有 URL 前面加上
/flex。在上例中,內容根目錄為 /flex。利用此處所提供的資訊,您可以縮短第一次
要求應用程式的啟動時間,因為 Flex 並不需要編譯 MXML 檔案。預先編譯應用程
式也可讓您在不需要原始碼的情況下散佈應用程式。您可使用 ant 或其他建置工具來
封裝 mxmlc 功能,並將 HTML shell 建置到自動化流程中。
如需建立 HTML 封套的更多資訊,請參閱 Flex 說明文件,網址為:
http://livedocs.macromedia.com/flex/1/flex_docs/ 38_dep24.htm -
wp147786。

26
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

ഋဍᒵ໶
您有兩種選擇可部署 Flex。您可以運用現有的硬體和應用程式伺服器,也可以將
Flex 部署在專屬的系統上。運用現有硬體是提高投資報酬的最佳方法。您可能擔心將
Flex 加入現有環境會使伺服器負載變重,造成現有基礎架構極大負擔。事實正好相
反。使用 Flex 反而可以減少伺服器負載。
將現有 JSP 或以 servlet 為基礎的應用程式改造成 Rich Internet Application
(RIA),可降低每個要求傳遞的資料量,進而減少伺服器負載。而且,HTML 應用程
式是以網頁為基礎,當有資訊提交到伺服器,或是用戶端從一網頁瀏覽到另一網頁
時,就需要重新整理整個網頁。每一次網頁載入都會佔用網路頻寬及伺服器資源。
RIA 運作起來就像桌面應用程式,而不是一系列的網頁。Flash Player 把用戶端介面
當作單一無中斷的流程,當用戶端從應用程式的一區段移到另一區段時,並不需要從
伺服器載入網頁。使用 RIA,瀏覽器只需載入 SWF 檔案一次,後續的所有要求都是
使用 XML 或 AMF 的較小資料導向要求。
另一種部署 Flex 但比較不建議的選擇是建立專屬 Flex 環境。在這種模型中,現有基
礎架構是透過網頁服務或 XML 餵送來提供資料連接功能。這種模型會大幅增加成本
及系統負荷,因為您必須在打算部署 Flex 的位置安裝並設定新硬體以及 J2EE 應用
程式伺服器。
JVM 及 J2EE 伺服器微調注意事項:Flex 支援各種 J2EE 應用程式伺服器,因此
很難列出針對伺服器效能微調的特定動作。最好是先到應用程式伺服器廠商網站尋找
有關微調的資源。Flex 中的編譯器及資料服務可能會在嚴重負載的情況下使用大量的
短期物件。由於需經常使用廢棄項目收集功能,有時候可能會導致延遲。如果您的
JVM 廠商與 J2EE 應用程式伺服器廠商不同,您可能需要瞭解如何微調 JVM 及廢
棄項目收集功能。

ବᄇௌՌϏ‫ ޟ‬Flex ᔖҢแԒ໌՗ਝ૖ཌ፡ᇄϷ‫ݙ‬


請儘早並不時測試應用程式的效能!建議您最好能夠進行反覆測試,及早發現有問題
的部分並予以解決,而不要等到應用程式開發階段接近尾聲之際,才急忙將效能增強
功能擠入效能不佳的現有程式碼。下面的小節將說明測試 Flex 用戶端效能的兩種方
法:使用 ActionScript 設定器,或使用一段程式碼來計算應用程式起始化的時間。
我們也提供了好用的解決方案,透過 ActionScript 的 getTimer() 方法來計算元件
及資料動作的時間。本節最後將說明負載測試。

27
‫ٺ‬Ң ActionScript ೩ۡᏢ

ActionScript 設定器可記錄 Flash Player 在 ActionScript 中執行工作所花的時


間。最常見的用途是使用設定器來判斷執行 ActionScript 函式或方法所需的時間、
被呼叫的頻率,以及在其子系中執行所花的時間。這可幫助找出哪些物件初始化可能
花了太多時間,或者是否有因為大量使用圖形或編碼不佳而造成瓶頸。不過,執行設
定器會對進行分析的應用程式加重負擔。這是因為設定器用 Flash Debug Player 版
本來執行,此版本的執行速度要比正式版來得慢。從設定器傳回的結果應以相對的角
度來分析,而不是將其視為正確的絕對時間。在 Flash Player 正式版中執行應用程
式所產生的結果,會與用 Flash Debug Player 執行相同應用程式的結果不同。如需
安裝和執行 ActionScript 設定器的詳細資訊,請參閱 Flex 說明文件。Macromedia
Flex 技術傳播人員 Christophe Coenraets 也針對如何使用 ActionScript 設定器最
佳化應用程式效能,寫了一篇很不錯的部落格日誌,網址為:
www.markme.com/cc/archives/2004_04.cfm。

ॎᆗᔖҢแԒߑۖϽਢ໢

另一個更簡單的效能分析方法就是使用程式碼來估算啟動時間。下面這一段程式碼可
計算應用程式初始化時間(也就是 Application 物件建立、計算、排列及繪製所有子
物件所需的時間);這並不包括下載用戶端 SWF 或任何伺服器端處理(像是檢查
Flash Player 版本、檢查 SWF 快取等)所需的時間。下面的例子顯示範例 Flex 應
用程式在瀏覽器中被叫用時,會出現載有控制項的簡單表單,初始化所花的時間會輸
出在標籤中。
<?xml version="1.0" encoding="iso-8859-1"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
creationComplete="doLater(this,'doneNow')">
<mx:Script><![CDATA[
var dp = [{food:"apple", type:"fruit", color:"red"},
{food:"potato", type:"vegetable", color:"brown"}, {food:"pear",
type:"fruit", color:"green"},
{food:"orange", type:"fruit",
color:"orange"},{food:"spinach", type:"vegetable",
color:"green"},{food:"beet", type:"vegetable", color:"red"}];
function doneNow()
{
doLater(this, "reallyDoneNow");
}
function reallyDoneNow()
{
timerLabel.text += getTimer() + " ms"
}
]]></mx:Script>
<mx:Form>
<mx:FormHeading label="Sample Form" />
<mx:FormItem label="List Control">
<mx:List dataProvider="{dp}"
labelField="food"/>
</mx:FormItem>
<mx:FormItem label="DataGrid control">
<mx:DataGrid width="200"
dataProvider="{dp}"/>
</mx:FormItem>
<mx:FormItem label="Date controls">
<mx:DateChooser />

28
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

<mx:DateField />
</mx:FormItem>
<mx:FormItem label="Load Time">
<mx:Label id="timerLabel"
fontSize="12" fontWeight="bold" text="The application
initialized in "/>
</mx:FormItem>
</mx:Form>
</mx:Application>

首先是要取得應用程式啟動時間的基準讀數。請確定您已結束所有其他執行中的應用
程式、確認是否使用 Flash Player 的正式版,然後執行應用程式三次來取得三次初
始化時間。將這三次時間平均起來就是基準讀數。當您在進行效能微調時,應確定啟
動時間的確有比較快。
這段程式碼也可協助您找出應用程式執行最慢的部分,並確定是否能夠予以加速。若
要這麼做,請選擇性地將應用程式的部分移除,看看單一部分的啟動時間是否與整個
應用程式的啟動時間相當。此一反覆進行的程序可找出應用程式有問題的部分。比如
說,此一方法可能會顯示整個應用程式的啟動時間為 12 秒,而載入其中的「檢視
B」就需要 6 秒。「檢視 B」就是問題所在,您可加以探討並尋求提升效能的辦法。
這個方法比設定和使用 ActionScript 設定器來得簡單,不過所產生的資訊就沒那麼
詳細。

‫ٺ‬Ң getTimer() ॎᆗϯӇ‫ڷ‬ၥਟଢ଼հ‫ޟ‬ਢ໢

getTimer() 函式是一個非常有用的 ActionScript 函式,可傳回 Flex 用戶端應用程


式已在瀏覽器中執行的毫秒數。將 getTimer() 函式呼叫附加到事件可讓您計算元件
和資料動作的時間。本文共同作者 Brandon Purcell 在 Macromedia 擔任支援工程
師,針對如何使用 getTimer() 函式計算 Flex 資料服務呼叫的時間,撰寫了一篇部
落格日誌,網址為:
www.bpurcell.org/blog/index.cfm?mode=entry&entry=1017。

ବᄇௌ‫ ޟ‬Flex ᔖҢแԒ໌՗॒ၷกၐ

Flex 應用程式的效能與現有應用程式及基礎架構密切相關。比如說,Flex 應用程式


伺服器和資料服務每秒可支援幾百個要求。但如果您的網頁服務或遠端物件每秒只能
支援 35 個要求,那麼網頁服務就成了瓶頸而無法進一步擴充。這就是為什麼您必須
針對應用程式的個別層逐一測試。下面幾節說明如何針對 Flex 應用程式進行負載測試。

॒ၷกၐώ‫ڎ‬

首先在不使用 Flex proxy 的情況下對每項資料服務進行負載測試。如果您使用由


servlet 提供的網頁服務或 XML 餵送,請使用負載測試工具來估算每秒可支援的最大
要求數。接著再以透過 Flex proxy 的方式執行同樣的測試,因為所有流量都是從
Flash 用戶端傳送到 proxy,然後再由 proxy 將要求傳送到網頁服務或 HTTP 餵
送。
目前有幾種負載測試工具可供選擇,有些是免費的,有些則要花上數萬元。在開發及
規劃階段,用免費工具來對個別服務(如網頁服務、遠端物件或 XML 餵送等)進行
負載測試就夠了。不過,若要對完成的應用程式進行負載測試並隨機化要求資料,請
使用付費工具。下表列出常見的免費及付費負載測試工具。

29
表 1: 負載測試工具

免費工具 付費工具

Microsoft Web Application Stress 工具 SegueSilkPerformer


OpenSTA Mercury LoadRunner 或 LoadTest
Apache JMeter Emperix e-Test Suite
Apache Bench

॒ၷกၐጒ‫ٽ‬

在開發期間,測試 Flex 應用程式所使用的每項服務。做法很簡單,請使用上表所列


的免費工具之一來記錄 Flash 用戶端與伺服器之間的互動,然後在多使用者的情況下
重放所記錄的要求/回應。本節將說明使用不同方法與資料服務的幾個案例。

案例 1

常見的方法之一是透過將 XML 提供給 Flex 應用程式的 JSP 或 servlet,並使用


Flex 中的 <mx:HTTPService> 標籤叫用。建立了使用 XML 餵送服務的應用程式部
分之後,進行負載測試來確保後端服務能夠支援實際執行的負載。由於多數開發系統
都不提供實際執行負載量,因此您應使用可反映實際執行系統的中繼環境。使用中繼
系統及測試工具,您便能記錄瀏覽器與伺服器之間所發生的流量。測試工具會記錄流
量,並可在多個執行緒(或使用者)的情況下予以重放來模擬實際執行的負載量。必
須注意的是,您在此階段只測試資料服務,而不測試載入 SWF 檔案或 Flex 提供的
其他服務。將其他要求從記錄的 script 刪除。下面這段程式碼顯示 Microsoft WAS
所記錄範例 script 中的要求:
GET /sharedapps/xmltest/WeeklyReport.mxml
GET /flex-internal?action=js
GET /sharedapps/xmltest/WeeklyReport.mxml.swf
GET /flex-internal/history/history.html
POST /flex/flashproxy
(post data
transport=http%2Dget&target=http%3A%2F%2F192%2E169%2E1%2E24%3A
8100%2Fsharedapps%2Fxmltest%2Fxml%2Ejsp)
GET /flex-internal?action=swf

請刪除 POST /flex/flashproxy 以外的所有要求,只針對 XML 餵送進行負載測


試。稍後在實際執行之前,再對傳送到伺服器的所有要求進行負載測試。在執行了第
一次負載測試後,您便得到基準值。接著您可修改程式碼或微調伺服器來改善數據,
直到達到目標為止。請使用此方法來測試 Flex 所使用的任何伺服器端資源。

ਰ‫ ٽ‬2

有時您可能會發現 Flex proxy 服務、網路或某個未知點是瓶頸所在。要解決此問


題,首先請排除終端服務。為了找出基準最大值,您應將 HTTPService 要求指向靜
態文件。若要這麼做,請要求餵送 XML 檔案的 JSP 或 servlet、將其儲存到靜態
XML 檔案,然後再放入 webroot 中。將 HTTPService 的 URL 改成指向此靜態文
件,然後再次執行負載測試。這不但可推斷出最大值,也可找出其他瓶頸。

30
Flex Application ਝ૖Ȉ
‫׽‬๡ҢИᆒᔖҢแԒᇄթ݈Ꮲਝ૖‫ޟ‬ඪҰᇄ‫׬‬೚

用 Flex 中的 <mx:WebService> 標籤對網頁服務進行負載測試的步驟也幾乎相同。在


檢視流量記錄時,您可能會發現 SWF 檔案第一次載入時,會傳送要求至 WSDL 來
載入有關網頁服務的資訊。當 Flex 應用程式載入時,SWF 檔案就會針對每個用戶端
傳送一次此要求。傳送 WSDL 要求之後,接著會對網頁服務中的方法傳送要求。若
您是對網頁服務進行負載測試,您可能會希望將 WSDL 叫用與方法呼叫分開測試,
因為針對此叫用提出要求的頻率大不如服務的方法呼叫。有些負載測試工具可讓您使
用不同的 script 來設定比例,讓測試模型儘量接近實際狀況。

ਰ‫ ٽ‬3

許多付費工具也提供強大的描述語言讓您自訂 script 並隨機化傳送到要求的資料。比


如說,假設您正在測試網站的登入部分,您不會希望 script 中是由同樣的使用者不斷
地做登入動作。而是用 script 隨機選取一組使用者,在負載測試的整個過程中模擬不
同的使用者登入。
透過用 AMF 編碼的 RemoteObject 進行負載測試也有一定的難度。SOAP 在傳送到
伺服器的要求中使用 XML,因此很容易描述 XML 資料的部分將採行隨機選取。
AMF 是二進位通訊協定,傳送到 Flash 閘道的要求資料也是二進位,因此不但難以
讀取傳送內容,也不易將要求描述成包含隨機資料。像是 Segue 等銷售負載測試工
具的廠商便將 AMF 通訊協定內建在測試套件當中,以簡化此一程序。
在開發階段接近尾聲之際,您應執行幾項全面的負載測試。這時最好使用前面所提及
的付費工具。您將需要記錄使用者會在應用程式當中所採取的幾個常見路徑。記錄了
不同的路徑後,您可能需要修改每個 script,來隨機選取傳送到伺服器的資料。您接
著可對伺服器執行 script,同時監視後端的幾個不同部分。您需要在應用程式及資料
庫伺服器上監視的部分包括:CPU、JVM 堆疊使用情況、網路以及應用程式伺服器
提供來進行監視的任何工具。
完成測試後,請分析結果並嘗試找出花最長時間處理的要求為何。目標是要找出應用
程式或伺服器的瓶頸以及最佳化任何部分。在最佳化應用程式之後,執行幾項長期的
MTBF (平均故障間隔時間)測試,確定在實際執行幾小時候,不會有先前已知或新
的問題導致當機。雖然不可能完全模擬出實際執行環境所發生的狀況,但雖不中亦不
遠矣。按照本節所提供的步驟及要訣施行後,您可以確定應用程式能夠在實際執行時
正常運作,將當機時間減至最少。

Ґ‫ีپ‬৤…
目前推出的 Flex 是 1.0 版。在 Flex 以後的版本中,Macromedia 打算加強現有的
Flex 機制、加入更多編譯器最佳化功能、解決物件建立時間等較大的效能問題,並加
入可縮短啟動時間的新功能。Flex 未來將推出來大幅提高啟動效能的功能之一便是執
行期共用程式庫(Runtime Shared Library;RSL)。利用 RSL,您可將共用資產
轉成獨立檔案,以供個別下載和快取。這麼一來,當程式庫不常變動,便可提高效
能,而且也可支援用大量小型 MXML 應用程式來建立網站,而不會受限於只能用單
一 MXML 應用程式。此外,下一版 Flash Player 也以大幅加強效能為目標。隨著
Flex 及 Flash Player 不斷進步,物件建立時間、物件繪製時間以及 ActionScript
處理時間也將愈來愈短,將可建立更強大、回應速度更快的 Flex 應用程式。

31
ཎَᇄЛධ
我們已盡一切努力確保本文及所附程式碼的正確性。歡迎您針對本文提出意見以及有
關 Flex 效能的問題。若要傳送給我們意見,請使用 Macromedia 網站上的意見表。
意見表的網址為: www.macromedia.com/support/email/tutorial/main.cgi。

ᜰܻհ‫ޱ‬
Brandon Purcell 在四年前進入 Macromedia/Allaire 擔任 ColdFusion 及 JRun
產品支援工程師。他在專業服務事業群 (Professional Services Group) 負責協助客
戶進行架構規劃、程式碼檢查、自訂訓練、負載測試及效能微調等工作。他也負責一
些專案,包括 macromedia.com 新網站的叢集、負載測試及部署工作。他在
Macromedia 任職期間支援的產品包括 ColdFusion、JRun、Flash Remoting,
並針對 ColdFusion 及 JRun 使用叢集與高可用性撰寫了相關的白皮書及文章。他
目前在支援 Flex 的伺服器支援組織 (Server Support Organization) 擔任特殊問題
工程師 (escalation engineer)。歡迎造訪他的網站:www.bpurcell.org。

Deepa Subramanian 在 Flex 團隊擔任 QA 工程師。剛從加州柏克萊大學 (Go


Bears!) 電腦科學系畢業的她加入 Marcomedia 只有一年多,對任何有關 Flex 的工
作都十分感興趣。

32

You might also like