最近一直在使用 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”的数据:
function on_click():
void
{
var list:XMLList
=
myXML.group;
var count:
int
=
0
;
for
(var i:
int
=
0
; i
<
list.length(); i
++
){
var persons:XMLList
=
list[i].person;
if
(persons.length()
==
1
&&
persons.@fullname
==
"
rosenjiang
"
){
count
++
;
}
else
{
for
(var j:
int
=
0
; j
<
persons.length(); j
++
){
if
(persons[j].@fullname
==
"
rosenjiang
"
){
count
++
;
}
}
}
}
Alert.show(count
+
"
个
"
);
}
上面的写法的确很傻,下面是改进之后的代码,关键部分只有一行:
function on_click():
void
{
var list:XMLList
=
myXML..person.(@fullname
==
"
rosenjiang
"
);
Alert.show(list.length()
+
"
个
"
);
}
通过合理使用 E4X
语法,顺利的避免了循环带来的性能问题。过了几天,来个新的需求,需要统计出在这个
XML 中有几个不同姓名的
person。思考片刻,我可不可以用眼睛数出来啊?这里有
3 个......
好吧,看来又是循环问题,第一个想到的是用两个嵌套
for 循环来进行排除处理,这是最直观的想法......
下面我介绍下如何用
ArrayCollection 并只使用一个循环来计算个数。由于
Flex 里面不支持 Map
类型,而我 Google
了一圈,且 RIACN
论坛上网友的 Map
实现性能都不行,遂打算用 ArrayCollection
模拟 Map 进行操作:
import
mx.collections.
*
;
function on_click():
void
{
var list:XMLList
=
myXML..person;
var ac:ArrayCollection
=
new
ArrayCollection();
for
each (var item:XML in list){
var fullname:String
=
item.@fullname;
if
(ac.getItemIndex(fullname)
==
-
1
){
ac.addItem(fullname);
}
}
Alert.show(ac.length
+
"
个
"
);
}
上面代码没什么过多解释,思路是取出一个
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!
请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:
http://www.blogjava.net/rosen