最近一直在使用 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