天天看點

用JSON技術加快AJAX程式開發

用JSON技術加快AJAX程式開發

朱先忠 編譯

一、引言

當微軟把ActiveX XMLHTTP對象納入到JavaScript的Internet Explorer實作中時,它實際上已經為Web應用程式的又一次革命(異步JavaScript+XML,簡稱AJAX)埋下了“火種”。今天,Firefox,Safari,Opera及其它浏覽器都支援XMLHttpRequest對象,正是這些支援最終才導緻了諸如colr.org,backpackit.com和maps.google.com等著名網站的産生。盡管這些網站(不止這些)所提供的應用程式運作于一種浏覽器中,但是它們在行為和外觀上卻極類似于傳統的桌面應用程式。

在AJAX技術中,在使用者觀看并與頁面互動的同時(這正相應于AJAX中的“異步”部分),由頁面中的JavaScript負責把資料請求發送到一個Web伺服器。這些請求隻是一些普通的HTTP請求,與浏覽器用于頁面(連同其中的任何圖像,層疊式樣表等内容)檢索的HTTP完全相同。同時,XMLHttpRequest對象可以用于檢索任何類型的資料,而不僅僅是XML類型。例如,JavaScript可以使用XMLHttpRequest來檢索一個來自于Web伺服器的普通文本文本并且把它的内容顯示于一個表單中。

通過查找位于資料之前的“content-type”頭部,XMLHttpRequest對象分析從Web伺服器傳回的資料的MIME類型。例如,如果這些資料的MIME類型是“text/plain”,那麼你可以通過分析XMLHttpRequest對象的responseText屬性來存取它;然而,如果其MIME類型為“text/xml”,那麼XMLHttpRequest對象必須采取額外的措施:它要在傳回的文檔對象上運作一個XML分析器并在記憶體中建構一棵文檔對象模型(DOM)樹來描述該文檔,并且還要使其可用于responseXML屬性。然後,你才可以使用JavaScript的标準DOM方法在樹中導航并檢索元素、屬性及位于該DOM樹中的其它文本。

雖然XML是進行資料交換的标準方式,但是通常它不是最好的方式。盡管XML可以把結構和中繼資料添加到資料上,但是它使用了一種相當繁瑣的方式。XML還有一種相對複雜的文法,因而需要一種分析器對之進行專門分析。在JavaScript中,XML必須被分析成一棵以備後用的DOM樹。并且,一旦你建構了這棵DOM樹,你還必須在其中導航以便建立相應的JavaScript對象或者以其它方式在你的用戶端Web應用程式中使用XML資料。

幸好,你還有另外更好的可選方案。

二、JSON簡介 javascript object notation

JavaScript對象标志,簡稱JSON,是一種描述資料的輕量級文法。JSON的優越性基于這樣的事實:它本身就是JavaScript語言的一個子集。你會在後面看到這種特征的重要性。首先,讓我們比較一下JSON和XML的原始文法。

XML和JSON都使用結構化方法來标記資料。例如,一個位址簿應用程式可能提供一個Web服務—它将以XML形式生成如下的位址卡片:

<?xml version='1.0' encoding='UTF-8'?>

<card>

<fullname>Sean Kelly</fullname>

<org>SK Consulting</org>

<emailaddrs>

</emailaddrs>

<telephones>

<tel type='work' pref='1'>+1 214 555 1212</tel>

<tel type='fax'>+1 214 555 1213</tel>

<tel type='mobile'>+1 214 555 1214</tel>

</telephones>

<addresses>

<address type='work' format='us'>1234 Main St

Springfield, TX 78080-1216</address>

<address type='home' format='us'>5678 Main St

Springfield, TX 78080-1316</address>

</addresses>

<urls>

</urls>

</card>

而使用JSON來表達,上面的形式将變成如下模樣:

{

"fullname": "Sean Kelly",

"org": "SK Consulting",

"emailaddrs": [

],

"teleph [

{"type": "work", "pref": 1, "value": "+1 214 555 1212"},

{"type": "fax", "value": "+1 214 555 1213"},

{"type": "mobile", "value": "+1 214 555 1214"}

"addresses": [

{"type": "work", "format": "us",

"value": "1234 Main StnSpringfield, TX 78080-1216"},

{"type": "home", "format": "us",

"value": "5678 Main StnSpringfield, TX 78080-1316"}

"urls": [

{"type": "work", "value": "http://seankelly.biz/"},

{"type": "home", "value": "http://seankelly.tv/"}

]

}

正如你所見,JSON也提供了一種具有嵌套資料元素的結構,就象XML一樣。與XML一樣,JSON也是基于文本的,且它們都使用Unicode編碼,且其與XML一樣具有可讀性。主觀上來看,JSON更為清晰且備援更少些。JSON網站提供了對JSON文法的嚴格描述,隻是描述較簡短。從總體來看,XML比較适合于标記文檔,而JSON卻更适于進行資料交換處理。一個JSON文檔的每一個執行個體都負責描述一個對象—具體的描述是通過使用嵌套的對象,數組,字元串,數字,布爾值或null值來實作的。

上面位址卡例子的JSON版本更為小些,僅占用大約682位元組的空間,而XML版本需要744位元組空間。當然,這不是什麼驚人的節省。其實,JSON的真正優點在于資料分析方面。

三、JSON與XML資料分析對比

借助于XMLHttpRequest對象,你可以從自己的基于AJAX的應用程式内部檢索XML和JSON檔案。典型情況下,你可以使用類似如下的互動:

var req = new XMLHttpRequest();

req.open("GET","http://localhost/addr?cardID=32", /*async*/true);

req. = myHandler;

req.send(/*no params*/null);

随着對Web伺服器的不斷響應,被你傳遞的處理器函數(在本例中是myHandler)被反複調用,這種特征提供給你一種時機—及早地取消事務,更新一個進度條,等等。通常,你隻是在Web請求完成時才采取行動(應用傳回的資料)。

為了處理上面位址卡程式的XML版本,myHandler的編碼可以類似如下:

function myHandler() {

if (req.readyState == 4 /*完成*/) {

//用第一個街道位址更新表單中的位址域

var addrField = document.getElementById('addr');

var root = req.responseXML;

var addrsElem = root.getElementsByTagName('addresses')[0];

var firstAddr = addrsElem.getElementsByTagName('address')[0];

var addrText = fistAddr.firstChild;

var addrValue = addrText.nodeValue;

addrField.value = addrValue;

注意,你不必自己分析XML文檔,分析任務可以由XMLHttpRequest對象為你自動完成。之後,這個XMLHttpRequest對象使得由分析生成的DOM樹可應用于responseXML屬性中。然後,你可以借助這個responseXML屬性并調用getElementsByTagName方法來查找文檔中的addresses部分,但僅能使用找到的第一個(其實隻有一個)。然後,你再次在找到的address上調用getElementsByTagName方法來查找下一層中的第一個address元素,然後再次使用找到的第一個address……然後,你得到該元素的第一個DOM子結點(它是一個文本結點)并得到該結點的值(它正是你想找的街道位址)。最後,你就可以在表單域中顯示它。

顯然,這是一項工作量很大的工作!現在,讓我們試用一下JSON:

if (req.readyState == 4 /*complete*/) {

var card = eval('(' + req.resp + ')');

addrField.value = card.addresses[0].value;

你需要做的第一件事情是手工地分析JSON響應。然而,因為JSON是JavaScript的一個子集,是以你可以通過調用eval方法使用JavaScript自己的編譯器來完成這些。分析JSON是非常簡單的!而且,在産生于JSON中的一個對象中導航與在任何JavaScript對象中導航完全一樣。這比在DOM樹中導航要容易得多。例如:

•card.addresses[0].value對應第一條街道位址:“1234 Main Stb &”;

•card.addresses[0].type對應位址的類型:“work”;

•card.addresses[1]對應一個家庭位址對象;

•card.fullname對應卡片名:“Sean Kelly”。

如果仔細觀察,那麼你可能注意到,示例程式的XML版本至少要處理包含在文檔中的一個對象—根文檔元素card。這在JSON版本中是不存在的。為什麼?如果你曾開發過存取一個Web服務的JavaScript,那麼你就會知道你要從Web服務中取回什麼。然而,你可以在JSON中包括下面一種更為簡練的形式:

{"card": {"fullname": ...}}

通過使用這一技術,你的JSON檔案總是以一個對象開頭并且用單個命名的屬性來标記該對象的“類型”。

四、JSON的快速可靠性

JSON能夠生成更小的文檔,且其在JavaScript腳本中更易于使用。XMLHttpRequest能夠為你自動分析XML文檔,然而你必須手工分析JSON。這樣以來,你可能質疑:分析JSON是否比分析XML更慢?對比JSON,我針對上面的位址卡測試了嵌入到XMLHttpRequest中的XML分析器—通過把這些資料置入上千次的循環中。最終結果表明,分析JSON比分析XML快大約10倍!如果想實作AJAX程式的行為類似于桌面應用程式,那麼速度就是一切。很明顯,JSON是勝者。

當然,你不可能一直控制為你的AJAX應用程式産生資料的伺服器端。你可以使用一種第三方伺服器來處理你的資料,而且讓該伺服器僅提供XML輸出。然而,如果該伺服器中恰巧能夠提供JSON支援,那麼你能否确定并敢于使用這一支援?

注意,在上面的示例中,你是直接把響應文本傳遞到一個對eval的調用中。如果你信任并控制了伺服器,這是沒有問題的;然而,另外一些情況下,一個惡意的伺服器有可能給你的浏覽器執行帶來危險操作。為此,你最好使用一個用JavaScript編寫的JSON分析器。幸好,已經存在可用的分析器了。

談到分析器,Python迷們可能還沒有注意到,JSON不僅是JavaScript的一個子集,而且它還是Python的一個子集。你可以直接在Python中使用JSON,或利用一種安全的JSON分析器。現在,針對于JSON的分析器也大量地存在于其它語言中;你可以參考JSON.org網站來選擇使用相應的分析器。

五、伺服器端技術對JSON的支援

到目前為止,我們一直集中于讨論如何把JSON應用于用戶端浏覽器上的基于AJAX技術的Web應用程式。當然,Web伺服器端必須存在一定的技術支援才能實作首先生成JSON,然後由用戶端使用JSON。幸好,基于現有資料結建構立JSON是一件相當直接的事情。另外,一些Web應用程式架構(例如TurboGears)已經自動包括支援JSON輸出。

另外,商業Web服務供應商也都特别關注JSON。Yahoo最近在其Web服務中大量地加入對JSON的支援。Yahoo的多種搜尋服務,旅行規劃者,del.icio.us和高速公路交通服務都支援JSON輸出。無疑,其它一些主要的Web服務供應商也都會逐漸地提供對JSON的支援。

六、結論

JSON的基本思想是,把自己實作為JavaScript(和Pyth 2.0開發中XML資料操作的主要替代者。任何開發者,無論是開發标準桌面應用程式還是開發Web應用程式,隻要使用XML資料處理,都會欣賞JSON的簡易特征。最後,我衷心祝願JSON能加快你的基于AJAX技術的Web 2.0應用程式的開發。

繼續閱讀