Michael Chen's Blog

World in my view is a word of my view
posts - 2, comments - 4, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2005年12月30日

QuirksBlog: The AJAX response: XML, HTML, or JSON?

早先这篇文章在TSS上贴出的时候,我很快的浏览,便一眼看出这篇文章作者所处的角度。事实上,AJAX概念的不完整和不严密性——异步的JavaScript + XML——导致作者将AJAX的输出分为三种类型:XML, HTML片断和JSON对象字符串。

首先看XML。对于RPC的数据传输,XML从来都是当仁不二的选择。对于将对象序列化为XML字符串的方式,往往有两种选择,一种是将对象本身的属性作为节点进行输出,一种是利用语言的元数据特性进行序列化输出。两者存在较大不同。对于第一种,输出案例如下:

<books>
    
<book>
        
<title>JavaScript, the Definitive Guide</title>
        
<publisher>O'Reilly</publisher>
        
<author>David Flanagan</author>
        
<cover src="/images/cover_defguide.jpg" />
        
<blurb>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</blurb>
    
</book>
    
<book>
        
<title>DOM Scripting</title>
        
<publisher>Friends of Ed</publisher>
        
<author>Jeremy Keith</author>
        
<cover src="/images/cover_domscripting.jpg" />
        
<blurb>Praesent et diam a ligula facilisis venenatis.</blurb>
    
</book>
</books>


而对于第二种,输出案例如下:

<list>
    
<type>java.util.List</type>
    
<map>
        
<type>yourapp.domain.Book</type>
        
<string>title</string>
        
<string>JavaScript, the Definitive Guide</string>
        
<string>publisher</string>
        
<string>O'Reilly</string>
        
<string>author</string>
        
<string>David Flanagan</string>
        
<string>cover</string>
        
<string>/images/cover_defguide.jpg</string>
        
<string>blurb</string>
        
<string>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</string>

    
</map>
    
<map>
        
<type>yourapp.domain.Book</type>
        
<string>title</string>
        
<string>DOM Scripting</string>
        
<string>publisher</string>
        
<string>Friends of Ed</string>
        
<string>author</string>
        
<string>Jeremy Keith</string>
        
<string>cover</string>
        
<string>/images/cover_domscripting.jpg</string>
        
<string>blurb</string>
        
<string>Praesent et diam a ligula facilisis venenatis.</string>

    
</map>
</list>


前一种一般来说是同一进程内(同一JVM内)对对象进行序列化和反序列化的方法,在XML-Java绑定一类的框架中比较多见,例如XStream, JiBX, Castor等等。当同一进程内能够找到对象具备的正确类型时,这种序列化/反序列化设计和实现都不太困难,而且针对空值处理也比较容易。

可以看出,由于这种方式成本较低,有大量成熟的开源库可用,加上在AJAX中的X(ML)的“理论”指导下,许多开发者采用这种方式将对象输出给前台浏览 器,然后利用浏览器的XML能力进行输出显示。从那篇文章中可以看出,这种工作是纯粹的dirty work, 并且由于领域模型或者DTO的不同,输出的xml结构含义也不同,在对空值的处理上更是麻烦,在处理显示逻辑的时候,基本上很难在客户端对以这种方式传递 的XML以一种统一的方式进行还原。以这种方式来进行AJAX开发,小规模应用还不能显出弊端,但是大规模应用出现,领域对象较多时,必然出现怨言。而我 们使用AJAX的真实意图并非来无趣地去解析各种各样的XML,而是需要XML中代表的数据。至于XML是什么样子,除了调试阶段,没有人会关心。

第二种XML的序列化方式是绝大多数跨进程远程调用协议/框架所采取的方式。SOAP/WebService如此,XMLRPC如此,Buffalo采用 的Burlap也如此。这种远程调用的特征是,在协议约定的条件下,调用方和被调用方需要保证数据语义的完整性。拿什么保证?就是数据定义信息了。这些协 议的共同特征是采用谋一些标记来描述数据类型:int, long, float, string, list...这样定义完成后,只要根据协议,任何语言都能以一种通用的方式对数据进行还原。AJAX引擎的概念也就渐渐呈现——通过某一种协议,他就处 于中间的位置,负责将调用方的请求包装为协议,转化为执行方能够理解的动作加以执行;然后将执行结果转化为协议的值,传递给客户端,客户端引擎将协议内容 解析为能够理解的对象结构传递给客户端,然后就可以利用这个数据来显示了。XML-RPC如此,WebService如此,DWR如此,JSON如此, Buffalo也如此。

综上所述,纯粹使用领域模型特定的输出XML传递给客户端是一种相当原始的做法。他只在很低的层次上印证了所谓AJAX的概念。然而,这种概念的深入思维结果便是一个AJAX引擎。

文中提到的第二种输出方式:HTML——应该被看作WEB的一个特例,应该说这是历史因素、浏览器能力、设计者等多方因素达到的一个平衡。许多历史应用 中,大多采用将页面进行一定规则的分割,然后include或者jsp 2.0 tagfile的方式对公共区域进行处理,留下一小部分进行动态显示。这里举一个例子:查询,显示书籍列表。传统做法就是上面一个搜索条件输入文本框,下 面是搜索结果列表,处于同一个页面。原来的搜索方式每次提交都要刷新整个页面,用户体验不太好,现在需要改进。按照激进的Ajax做法应该是当搜索按钮点 击时,调用bookSearchService.search(String terms)的方法,取得结果列表,然后Ajax引擎处理结果数据,将数据反序列化为javascript对象,开发者利用这些对象,要么利用DOM, 要么利用JavaScript Template, 在页面对搜索结果进行展示。然而,问题出现了:

搜索结果太多了,用DOM操作速度太慢;
开发者人手不够,没有时间,而这个页面以前写过;

那么出现这种情况时,很可能的做法便是,见原来那个搜索结果页面刨去其他不相干的部分,留下搜索结果部分,然后利用一个resultDiv.innerHTML=xmlhttp.responseText完事。这样做,既达到了改善体验的效果,也提高了开发速度。

输出HTML另外一种方式文中也没有提及。事实上,HTML不仅仅作为片断,更重要的是作为页面视图的一部分。在buffalo的demo中,可以看到所 有的页面都被管理起来了,buffalo接管了视图的切换;这种设计也存在于gmail/163新版邮箱中。这个应用比上面的HTML片断的使用方式还要 重要,因为这里是缓存可以介入的地方。通过不同的缓存策略,可以将用户的实际和心理等待时间大大减少,从而进一步改善用户操作体验,提升产品竞争力。 (PS. 在Buffalo 1.3中将加入客户端缓存模块,无需你动手,buffalo为你缓存视图)

文中提及的第三种方式,JSON,根据第一部分的描述,应该比较清楚了。实际上他扮演了一个Ajax引擎的角色。这里不得不提的是,使用JSON的相当危 险的。因为他的协议表现与语言本身绑定太死。如果某一天,JSON协议变化了,那么使用JSON的应用基本上不可能应对这个变化——因为返回结果是 eval()得到的。而Buffalo将协议隐藏起来了,1.2版本甚至连服务器端的ServiceInvoker都将burlap实现依赖隔离开。现在 使用burlap,也许某一天不用了,buffalo的应用照样可以运行。因为里面的细节都是透明的,作为开发者,你只需要关注数据对象本身,而非用来描 述对象的那一堆字符。

posted @ 2005-12-30 09:16 Michael Chen 阅读(1812) | 评论 (2)编辑 收藏