QuirksBlog:
The AJAX response: XML, HTML, or JSON?
早先這篇文章在TSS上貼出的時(shí)候,我很快的瀏覽,便一眼看出這篇文章作者所處的角度。事實(shí)上,AJAX概念的不完整和不嚴(yán)密性——異步的JavaScript + XML——導(dǎo)致作者將AJAX的輸出分為三種類(lèi)型:XML, HTML片斷和JSON對(duì)象字符串。
首先看XML。對(duì)于RPC的數(shù)據(jù)傳輸,XML從來(lái)都是當(dāng)仁不二的選擇。對(duì)于將對(duì)象序列化為XML字符串的方式,往往有兩種選擇,一種是將對(duì)象本身的屬性作為節(jié)點(diǎn)進(jìn)行輸出,一種是利用語(yǔ)言的元數(shù)據(jù)特性進(jìn)行序列化輸出。兩者存在較大不同。對(duì)于第一種,輸出案例如下:
而對(duì)于第二種,輸出案例如下:
前一種一般來(lái)說(shuō)是同一進(jìn)程內(nèi)(同一JVM內(nèi))對(duì)對(duì)象進(jìn)行序列化和反序列化的方法,在XML-Java綁定一類(lèi)的框架中比較多見(jiàn),例如XStream, JiBX, Castor等等。當(dāng)同一進(jìn)程內(nèi)能夠找到對(duì)象具備的正確類(lèi)型時(shí),這種序列化/反序列化設(shè)計(jì)和實(shí)現(xiàn)都不太困難,而且針對(duì)空值處理也比較容易。
可以看出,由于這種方式成本較低,有大量成熟的開(kāi)源庫(kù)可用,加上在AJAX中的X(ML)的“理論”指導(dǎo)下,許多開(kāi)發(fā)者采用這種方式將對(duì)象輸出給前臺(tái)瀏覽 器,然后利用瀏覽器的XML能力進(jìn)行輸出顯示。從那篇文章中可以看出,這種工作是純粹的dirty work, 并且由于領(lǐng)域模型或者DTO的不同,輸出的xml結(jié)構(gòu)含義也不同,在對(duì)空值的處理上更是麻煩,在處理顯示邏輯的時(shí)候,基本上很難在客戶(hù)端對(duì)以這種方式傳遞 的XML以一種統(tǒng)一的方式進(jìn)行還原。以這種方式來(lái)進(jìn)行AJAX開(kāi)發(fā),小規(guī)模應(yīng)用還不能顯出弊端,但是大規(guī)模應(yīng)用出現(xiàn),領(lǐng)域?qū)ο筝^多時(shí),必然出現(xiàn)怨言。而我 們使用AJAX的真實(shí)意圖并非來(lái)無(wú)趣地去解析各種各樣的XML,而是需要XML中代表的數(shù)據(jù)。至于XML是什么樣子,除了調(diào)試階段,沒(méi)有人會(huì)關(guān)心。
第二種XML的序列化方式是絕大多數(shù)跨進(jìn)程遠(yuǎn)程調(diào)用協(xié)議/框架所采取的方式。SOAP/WebService如此,XMLRPC如此,Buffalo采用 的Burlap也如此。這種遠(yuǎn)程調(diào)用的特征是,在協(xié)議約定的條件下,調(diào)用方和被調(diào)用方需要保證數(shù)據(jù)語(yǔ)義的完整性。拿什么保證?就是數(shù)據(jù)定義信息了。這些協(xié) 議的共同特征是采用謀一些標(biāo)記來(lái)描述數(shù)據(jù)類(lèi)型:int, long, float, string, list...這樣定義完成后,只要根據(jù)協(xié)議,任何語(yǔ)言都能以一種通用的方式對(duì)數(shù)據(jù)進(jìn)行還原。AJAX引擎的概念也就漸漸呈現(xiàn)——通過(guò)某一種協(xié)議,他就處 于中間的位置,負(fù)責(zé)將調(diào)用方的請(qǐng)求包裝為協(xié)議,轉(zhuǎn)化為執(zhí)行方能夠理解的動(dòng)作加以執(zhí)行;然后將執(zhí)行結(jié)果轉(zhuǎn)化為協(xié)議的值,傳遞給客戶(hù)端,客戶(hù)端引擎將協(xié)議內(nèi)容 解析為能夠理解的對(duì)象結(jié)構(gòu)傳遞給客戶(hù)端,然后就可以利用這個(gè)數(shù)據(jù)來(lái)顯示了。XML-RPC如此,WebService如此,DWR如此,JSON如此, Buffalo也如此。
綜上所述,純粹使用領(lǐng)域模型特定的輸出XML傳遞給客戶(hù)端是一種相當(dāng)原始的做法。他只在很低的層次上印證了所謂AJAX的概念。然而,這種概念的深入思維結(jié)果便是一個(gè)AJAX引擎。
文中提到的第二種輸出方式:HTML——應(yīng)該被看作WEB的一個(gè)特例,應(yīng)該說(shuō)這是歷史因素、瀏覽器能力、設(shè)計(jì)者等多方因素達(dá)到的一個(gè)平衡。許多歷史應(yīng)用 中,大多采用將頁(yè)面進(jìn)行一定規(guī)則的分割,然后include或者jsp 2.0 tagfile的方式對(duì)公共區(qū)域進(jìn)行處理,留下一小部分進(jìn)行動(dòng)態(tài)顯示。這里舉一個(gè)例子:查詢(xún),顯示書(shū)籍列表。傳統(tǒng)做法就是上面一個(gè)搜索條件輸入文本框,下 面是搜索結(jié)果列表,處于同一個(gè)頁(yè)面。原來(lái)的搜索方式每次提交都要刷新整個(gè)頁(yè)面,用戶(hù)體驗(yàn)不太好,現(xiàn)在需要改進(jìn)。按照激進(jìn)的Ajax做法應(yīng)該是當(dāng)搜索按鈕點(diǎn) 擊時(shí),調(diào)用bookSearchService.search(String terms)的方法,取得結(jié)果列表,然后Ajax引擎處理結(jié)果數(shù)據(jù),將數(shù)據(jù)反序列化為javascript對(duì)象,開(kāi)發(fā)者利用這些對(duì)象,要么利用DOM, 要么利用JavaScript Template, 在頁(yè)面對(duì)搜索結(jié)果進(jìn)行展示。然而,問(wèn)題出現(xiàn)了:
搜索結(jié)果太多了,用DOM操作速度太慢;
開(kāi)發(fā)者人手不夠,沒(méi)有時(shí)間,而這個(gè)頁(yè)面以前寫(xiě)過(guò);
那么出現(xiàn)這種情況時(shí),很可能的做法便是,見(jiàn)原來(lái)那個(gè)搜索結(jié)果頁(yè)面刨去其他不相干的部分,留下搜索結(jié)果部分,然后利用一個(gè)resultDiv.innerHTML=xmlhttp.responseText完事。這樣做,既達(dá)到了改善體驗(yàn)的效果,也提高了開(kāi)發(fā)速度。
輸出HTML另外一種方式文中也沒(méi)有提及。事實(shí)上,HTML不僅僅作為片斷,更重要的是作為頁(yè)面視圖的一部分。在buffalo的demo中,可以看到所 有的頁(yè)面都被管理起來(lái)了,buffalo接管了視圖的切換;這種設(shè)計(jì)也存在于gmail/163新版郵箱中。這個(gè)應(yīng)用比上面的HTML片斷的使用方式還要 重要,因?yàn)檫@里是緩存可以介入的地方。通過(guò)不同的緩存策略,可以將用戶(hù)的實(shí)際和心理等待時(shí)間大大減少,從而進(jìn)一步改善用戶(hù)操作體驗(yàn),提升產(chǎn)品競(jìng)爭(zhēng)力。 (PS. 在Buffalo 1.3中將加入客戶(hù)端緩存模塊,無(wú)需你動(dòng)手,buffalo為你緩存視圖)
文中提及的第三種方式,JSON,根據(jù)第一部分的描述,應(yīng)該比較清楚了。實(shí)際上他扮演了一個(gè)Ajax引擎的角色。這里不得不提的是,使用JSON的相當(dāng)危 險(xiǎn)的。因?yàn)樗膮f(xié)議表現(xiàn)與語(yǔ)言本身綁定太死。如果某一天,JSON協(xié)議變化了,那么使用JSON的應(yīng)用基本上不可能應(yīng)對(duì)這個(gè)變化——因?yàn)榉祷亟Y(jié)果是 eval()得到的。而B(niǎo)uffalo將協(xié)議隱藏起來(lái)了,1.2版本甚至連服務(wù)器端的ServiceInvoker都將burlap實(shí)現(xiàn)依賴(lài)隔離開(kāi)。現(xiàn)在 使用burlap,也許某一天不用了,buffalo的應(yīng)用照樣可以運(yùn)行。因?yàn)槔锩娴募?xì)節(jié)都是透明的,作為開(kāi)發(fā)者,你只需要關(guān)注數(shù)據(jù)對(duì)象本身,而非用來(lái)描 述對(duì)象的那一堆字符。
早先這篇文章在TSS上貼出的時(shí)候,我很快的瀏覽,便一眼看出這篇文章作者所處的角度。事實(shí)上,AJAX概念的不完整和不嚴(yán)密性——異步的JavaScript + XML——導(dǎo)致作者將AJAX的輸出分為三種類(lèi)型:XML, HTML片斷和JSON對(duì)象字符串。
首先看XML。對(duì)于RPC的數(shù)據(jù)傳輸,XML從來(lái)都是當(dāng)仁不二的選擇。對(duì)于將對(duì)象序列化為XML字符串的方式,往往有兩種選擇,一種是將對(duì)象本身的屬性作為節(jié)點(diǎn)進(jìn)行輸出,一種是利用語(yǔ)言的元數(shù)據(jù)特性進(jìn)行序列化輸出。兩者存在較大不同。對(duì)于第一種,輸出案例如下:
<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>
<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>
而對(duì)于第二種,輸出案例如下:
<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>
<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>
前一種一般來(lái)說(shuō)是同一進(jìn)程內(nèi)(同一JVM內(nèi))對(duì)對(duì)象進(jìn)行序列化和反序列化的方法,在XML-Java綁定一類(lèi)的框架中比較多見(jiàn),例如XStream, JiBX, Castor等等。當(dāng)同一進(jìn)程內(nèi)能夠找到對(duì)象具備的正確類(lèi)型時(shí),這種序列化/反序列化設(shè)計(jì)和實(shí)現(xiàn)都不太困難,而且針對(duì)空值處理也比較容易。
可以看出,由于這種方式成本較低,有大量成熟的開(kāi)源庫(kù)可用,加上在AJAX中的X(ML)的“理論”指導(dǎo)下,許多開(kāi)發(fā)者采用這種方式將對(duì)象輸出給前臺(tái)瀏覽 器,然后利用瀏覽器的XML能力進(jìn)行輸出顯示。從那篇文章中可以看出,這種工作是純粹的dirty work, 并且由于領(lǐng)域模型或者DTO的不同,輸出的xml結(jié)構(gòu)含義也不同,在對(duì)空值的處理上更是麻煩,在處理顯示邏輯的時(shí)候,基本上很難在客戶(hù)端對(duì)以這種方式傳遞 的XML以一種統(tǒng)一的方式進(jìn)行還原。以這種方式來(lái)進(jìn)行AJAX開(kāi)發(fā),小規(guī)模應(yīng)用還不能顯出弊端,但是大規(guī)模應(yīng)用出現(xiàn),領(lǐng)域?qū)ο筝^多時(shí),必然出現(xiàn)怨言。而我 們使用AJAX的真實(shí)意圖并非來(lái)無(wú)趣地去解析各種各樣的XML,而是需要XML中代表的數(shù)據(jù)。至于XML是什么樣子,除了調(diào)試階段,沒(méi)有人會(huì)關(guān)心。
第二種XML的序列化方式是絕大多數(shù)跨進(jìn)程遠(yuǎn)程調(diào)用協(xié)議/框架所采取的方式。SOAP/WebService如此,XMLRPC如此,Buffalo采用 的Burlap也如此。這種遠(yuǎn)程調(diào)用的特征是,在協(xié)議約定的條件下,調(diào)用方和被調(diào)用方需要保證數(shù)據(jù)語(yǔ)義的完整性。拿什么保證?就是數(shù)據(jù)定義信息了。這些協(xié) 議的共同特征是采用謀一些標(biāo)記來(lái)描述數(shù)據(jù)類(lèi)型:int, long, float, string, list...這樣定義完成后,只要根據(jù)協(xié)議,任何語(yǔ)言都能以一種通用的方式對(duì)數(shù)據(jù)進(jìn)行還原。AJAX引擎的概念也就漸漸呈現(xiàn)——通過(guò)某一種協(xié)議,他就處 于中間的位置,負(fù)責(zé)將調(diào)用方的請(qǐng)求包裝為協(xié)議,轉(zhuǎn)化為執(zhí)行方能夠理解的動(dòng)作加以執(zhí)行;然后將執(zhí)行結(jié)果轉(zhuǎn)化為協(xié)議的值,傳遞給客戶(hù)端,客戶(hù)端引擎將協(xié)議內(nèi)容 解析為能夠理解的對(duì)象結(jié)構(gòu)傳遞給客戶(hù)端,然后就可以利用這個(gè)數(shù)據(jù)來(lái)顯示了。XML-RPC如此,WebService如此,DWR如此,JSON如此, Buffalo也如此。
綜上所述,純粹使用領(lǐng)域模型特定的輸出XML傳遞給客戶(hù)端是一種相當(dāng)原始的做法。他只在很低的層次上印證了所謂AJAX的概念。然而,這種概念的深入思維結(jié)果便是一個(gè)AJAX引擎。
文中提到的第二種輸出方式:HTML——應(yīng)該被看作WEB的一個(gè)特例,應(yīng)該說(shuō)這是歷史因素、瀏覽器能力、設(shè)計(jì)者等多方因素達(dá)到的一個(gè)平衡。許多歷史應(yīng)用 中,大多采用將頁(yè)面進(jìn)行一定規(guī)則的分割,然后include或者jsp 2.0 tagfile的方式對(duì)公共區(qū)域進(jìn)行處理,留下一小部分進(jìn)行動(dòng)態(tài)顯示。這里舉一個(gè)例子:查詢(xún),顯示書(shū)籍列表。傳統(tǒng)做法就是上面一個(gè)搜索條件輸入文本框,下 面是搜索結(jié)果列表,處于同一個(gè)頁(yè)面。原來(lái)的搜索方式每次提交都要刷新整個(gè)頁(yè)面,用戶(hù)體驗(yàn)不太好,現(xiàn)在需要改進(jìn)。按照激進(jìn)的Ajax做法應(yīng)該是當(dāng)搜索按鈕點(diǎn) 擊時(shí),調(diào)用bookSearchService.search(String terms)的方法,取得結(jié)果列表,然后Ajax引擎處理結(jié)果數(shù)據(jù),將數(shù)據(jù)反序列化為javascript對(duì)象,開(kāi)發(fā)者利用這些對(duì)象,要么利用DOM, 要么利用JavaScript Template, 在頁(yè)面對(duì)搜索結(jié)果進(jìn)行展示。然而,問(wèn)題出現(xiàn)了:
搜索結(jié)果太多了,用DOM操作速度太慢;
開(kāi)發(fā)者人手不夠,沒(méi)有時(shí)間,而這個(gè)頁(yè)面以前寫(xiě)過(guò);
那么出現(xiàn)這種情況時(shí),很可能的做法便是,見(jiàn)原來(lái)那個(gè)搜索結(jié)果頁(yè)面刨去其他不相干的部分,留下搜索結(jié)果部分,然后利用一個(gè)resultDiv.innerHTML=xmlhttp.responseText完事。這樣做,既達(dá)到了改善體驗(yàn)的效果,也提高了開(kāi)發(fā)速度。
輸出HTML另外一種方式文中也沒(méi)有提及。事實(shí)上,HTML不僅僅作為片斷,更重要的是作為頁(yè)面視圖的一部分。在buffalo的demo中,可以看到所 有的頁(yè)面都被管理起來(lái)了,buffalo接管了視圖的切換;這種設(shè)計(jì)也存在于gmail/163新版郵箱中。這個(gè)應(yīng)用比上面的HTML片斷的使用方式還要 重要,因?yàn)檫@里是緩存可以介入的地方。通過(guò)不同的緩存策略,可以將用戶(hù)的實(shí)際和心理等待時(shí)間大大減少,從而進(jìn)一步改善用戶(hù)操作體驗(yàn),提升產(chǎn)品競(jìng)爭(zhēng)力。 (PS. 在Buffalo 1.3中將加入客戶(hù)端緩存模塊,無(wú)需你動(dòng)手,buffalo為你緩存視圖)
文中提及的第三種方式,JSON,根據(jù)第一部分的描述,應(yīng)該比較清楚了。實(shí)際上他扮演了一個(gè)Ajax引擎的角色。這里不得不提的是,使用JSON的相當(dāng)危 險(xiǎn)的。因?yàn)樗膮f(xié)議表現(xiàn)與語(yǔ)言本身綁定太死。如果某一天,JSON協(xié)議變化了,那么使用JSON的應(yīng)用基本上不可能應(yīng)對(duì)這個(gè)變化——因?yàn)榉祷亟Y(jié)果是 eval()得到的。而B(niǎo)uffalo將協(xié)議隱藏起來(lái)了,1.2版本甚至連服務(wù)器端的ServiceInvoker都將burlap實(shí)現(xiàn)依賴(lài)隔離開(kāi)。現(xiàn)在 使用burlap,也許某一天不用了,buffalo的應(yīng)用照樣可以運(yùn)行。因?yàn)槔锩娴募?xì)節(jié)都是透明的,作為開(kāi)發(fā)者,你只需要關(guān)注數(shù)據(jù)對(duì)象本身,而非用來(lái)描 述對(duì)象的那一堆字符。
posted @ 2005-12-30 09:16 Michael Chen 閱讀(1822) | 評(píng)論 (2) | 編輯 收藏