最近一段時(shí)間,關(guān)心 Web 開(kāi)發(fā)的朋友在網(wǎng)絡(luò )上會(huì )經(jīng)常聽(tīng)到 Ajax 這個(gè) buzzword。使用 Google 搜索,會(huì )搜索到無(wú)數自稱(chēng)是 Ajax 的例子。這些例子的作者得意洋洋地展示自己學(xué)會(huì )了 xmlhttp 之后寫(xiě)出的 hello world,自以為已經(jīng)精通了 Ajax。
那么 Ajax 究竟是什么?它是不是就是等同于 xmlhttp 呢?我們先來(lái)從源頭說(shuō)起。
Ajax 這個(gè)詞的發(fā)明者是 Jesse James Garrett,他在這篇文章中發(fā)明了 AJAX 這個(gè)詞:
Ajax: A New Approach to Web Applications
點(diǎn)擊查看這篇文章發(fā)表在 2005 年 2 月 18 號??赡芙裉斓暮芏嗯笥堰€沒(méi)有讀過(guò)這篇文章,我來(lái)介紹一下其中的內容。
Ajax 是 Asynchronous JavaScript + XML 的縮寫(xiě),其中用到的主要的技術(shù)包括:
基于 XHTML/CSS 標準的展現
使用 DOM 的動(dòng)態(tài)顯示和交互
使用 XML 和 XSLT 的數據交換和處理
使用 XMLHttpRequest 的異步數據獲取
JavaScript 把所有的一切捆綁在一起
Ajax 的交互模型和傳統基于 HTML Form 的交互模型有著(zhù)非常大的區別。
作者通過(guò)以下這個(gè)圖對于傳統的交互模式和 Ajax 交互模式做了一個(gè)比較。
我們看到,在傳統的交互模式下,客戶(hù)端并無(wú)表示邏輯的執行,由服務(wù)器端執行所有的表示邏輯,然后把 HTML/CSS 傳給客戶(hù)端,客戶(hù)端僅僅做簡(jiǎn)單的展現。
傳統的交互模式最大的問(wèn)題就是任何哪怕是微小的交互行為都需要到服務(wù)器端走一趟,這樣所帶來(lái)大量的延遲令用戶(hù)感覺(jué)很不舒服,也降低了用戶(hù)的工作效率??赡墁F在 Web 大量用戶(hù)已經(jīng)習慣了等待一個(gè)頁(yè)面刷新的無(wú)聊時(shí)間,可是這不能成為我們開(kāi)發(fā)者推托有責任改善交互行為的借口。假設在用戶(hù)使用 B/S 應用之前還使用過(guò) C/S 應用,在 C/S 應用中難道會(huì )有這樣可笑的事情發(fā)生嗎?
解決之道是什么?我們再看一下 Ajax 的交互模式。
在客戶(hù)端多出來(lái)了一個(gè) Ajax engine,而且服務(wù)器傳給客戶(hù)端的已經(jīng)不再是 HTML/CSS,而是純的 XML 數據,客戶(hù)端通過(guò) XMLHttp 向服務(wù)器端發(fā)送請求。所有的表示邏輯在客戶(hù)端通過(guò) JS 腳本來(lái)執行,然后通過(guò)修改 DOM 來(lái)完成展現。
由于有了位于客戶(hù)端這個(gè)中間層,可以把原先必須在服務(wù)器端完成的很多交互工作放在了客戶(hù)端完成,而客戶(hù)端的 Ajax engine 的響應是即時(shí)的,因此用戶(hù)的交互體驗得到了極大的改善。我們可以通過(guò)下面這張圖來(lái)比較兩種交互模式下的時(shí)間分配。我們可以看出,傳統的基于 HTML Form 的交互模式下用戶(hù)的大量時(shí)間都浪費在了無(wú)聊的等待之上。這種新的交互模式的最大優(yōu)點(diǎn)就是改善了用戶(hù)的體驗。此外還有很多其它方面的優(yōu)點(diǎn),例如不需要刷新頁(yè)面、減少了服務(wù)器的處理負擔、減少了交換的數據量等等。
那么 Ajax 是不是一種神奇的新技術(shù)呢?完全不是,從 Ajax 所用到的上述核心技術(shù)來(lái)看,任何一種技術(shù)都是已經(jīng)成熟了多年的技術(shù),據我所知,最晚在 2001 年,所有這些技術(shù)都已經(jīng)成熟并且進(jìn)入了實(shí)用階段。因此,我僅僅是把 Ajax 看作是傳統的基于 XHTML/CSS/JS 開(kāi)發(fā)的復興。實(shí)際上我以前所在的公司已經(jīng)完全采用這種架構做 Web 開(kāi)發(fā)有 3 年之久。我們已經(jīng)完全摒棄了 HTML Form。所以當我看到這篇文章的時(shí)候想到,如果我們早發(fā)明一個(gè)詞,那這種新的 Web 開(kāi)發(fā)模式可能就不叫 Ajax 了。不過(guò)這也證明了我們在幾年前做出的決定還是有先見(jiàn)之明的。
雖然在這個(gè)詞出現很多年以前就已經(jīng)有大量的開(kāi)發(fā)人員采用這種開(kāi)發(fā)模式,不過(guò)現在既然出現了這個(gè)詞,起到了規范術(shù)語(yǔ)的作用。去年在 JavaEye 活動(dòng)上做 XMLHttp 開(kāi)發(fā)的講座時(shí)我感覺(jué)自己是相當另類(lèi)的一個(gè)人,因為那時(shí)候還沒(méi)有多少 J2EE 開(kāi)發(fā)人員會(huì )對 JS 感興趣?,F在 Ajax 越來(lái)越進(jìn)入 J2EE Web 開(kāi)發(fā)的主流領(lǐng)域,而且會(huì )長(cháng)期保持它的生命力。
5 月底 JavaEye 的活動(dòng)上聽(tīng)熊節的演講,什么也沒(méi)記住,只記住一個(gè)詞:古已有之。其實(shí) Ajax 也是古已有之。Ajax 也不過(guò)就是新瓶裝舊酒,但是它把以前由美工單獨使用的這些技術(shù)(至今仍然有大量的 J2EE 開(kāi)發(fā)人員認為寫(xiě) JS 完全是美工的任務(wù))完美地結合在了一起,產(chǎn)生出了巨大的價(jià)值。Ajax 是一種新的交互模式或者開(kāi)發(fā)模式,而不是一個(gè)現成的框架?;?Ajax 思想開(kāi)發(fā)的應用都可以稱(chēng)作是 Ajax 應用。Ajax 對于這些傳統的 J2EE 開(kāi)發(fā)人員不怎么關(guān)心的客戶(hù)端技術(shù)進(jìn)行重新包裝,對于企業(yè)應用產(chǎn)生了巨大的價(jià)值。我們知道表示層開(kāi)發(fā)始終是具有重大意義的,占用了開(kāi)發(fā)項目幾乎一半的工作量。而用戶(hù)很多時(shí)候就是看你的界面和交互,所以這部分是不能馬虎的。架構你可以稍微馬虎一點(diǎn),基于 Spring/Hibernate 差也不會(huì )差很多。但是界面和交互是用戶(hù)立刻能感受到的東西,是不能馬虎的。
目前 Google 為 Ajax 技術(shù)做出了巨大的投入,Google 這兩年推出的一些應用如 Gmail、Google Groups、Google Suggest、Google Maps 等等都采用了 Ajax 的技術(shù)。其中最為醒目和最復雜的應用就是 Google Map。下面我將 Google Maps 作為 Ajax 應用的一個(gè)典型為大家做一些介紹。
2、Ajax 之實(shí)例應用——Google Maps
在做這個(gè)演講之前,我參考網(wǎng)上的一些資料對 Google Maps 做了一些 hack 的工作。目前已經(jīng)可以做到除了地圖圖片要從 Google 請求外,其余所有的數據都在本地運行。
但是因為 Google Maps 前臺的代碼量比較大,并且是經(jīng)過(guò)混淆的。所以整理這些代碼花費了比較多的功夫。目前這個(gè)工作尚未全部完成。因此以下講述的內容僅僅是根據我目前的成果。
Google Maps 使用了那些技術(shù)?
Google Maps 所使用的技術(shù),基本上就是上面 Ajax 所提到的這些技術(shù)。
1. standards-based presentation using XHTML and CSS;
2. dynamic display and interaction using the Document Object Model;
3. data interchange and manipulation using XML and XSLT;
4. asynchronous data retrieval using XMLHttpRequest;
5. and JavaScript binding everything together.
Google Maps 每一張大的地圖實(shí)際上都是很多張小的 gif 貼圖。普通地圖每一張小圖片的大小為 128x128 像素,衛星地圖每一張小圖片的大小為 256x256 像素。每一張小圖片都有自己獨立的 URL,其格式為:
http://mt.google.com/mt?v=.1&x=50&y=20&zoom=4其中包括幾個(gè)參數:
v:當前版本號。.1 被推測為 0.1 版
x:圖片的 x 索引
y:圖片的 y 索引
zoom:圖片的縮放級別。
每張地圖需要哪些貼圖使用固定的算法算出。然后自動(dòng)像服務(wù)器請求這些貼圖。當地圖發(fā)生任何變化(例如:拖拽、移動(dòng)、縮放等等)時(shí),都會(huì )自動(dòng)像服務(wù)器請求需要的圖片。例如剛才我們看到了當地圖發(fā)生移動(dòng)時(shí),圖片會(huì )自動(dòng)補全新的顯示區域。所有的這些計算和處理,全部都是使用 JS 在瀏覽器端完成的。
因為瀏覽器有圖片的緩存功能,因此如果你經(jīng)常查看某個(gè)相同地區的地圖的話(huà),久而久之,瀏覽器會(huì )緩存大量的圖片,這樣你使用 Google Maps 的性能就會(huì )越來(lái)越好了。
Google Maps 還有搜索的功能,而且非常強大。我這里錄制了一個(gè)簡(jiǎn)單的演示。
Google Maps 還可以完成復雜的搜索,例如搜索 lax 這個(gè)地方的旅館,結果為:
點(diǎn)擊地圖右邊旅館條目,可以在地圖上面出現旅館的說(shuō)明。這個(gè)說(shuō)明是使用 XSLT 技術(shù)產(chǎn)生的。
還可以搜索兩點(diǎn)之間的路徑。例如搜索 jfk to 350 5th ave, new york,得到的結果就是帶有兩點(diǎn)之間路徑路徑的地圖。這里的路徑在 IE 上是使用 VML 畫(huà)的,而在其它瀏覽器上使用后臺自動(dòng)生成的透明 png 圖片輿地圖圖片疊加產(chǎn)生。因為 IE 完全是在客戶(hù)端完成,所以 IE 的性能會(huì )好一些。
另外 Google Maps 的地圖既可以加載在一個(gè) DIV 中,也可以加載在一個(gè) IFRame 中。熟悉 XMLHttp 的朋友知道,出現了 XMLHttp 后,需要通過(guò)隱藏的 IFrame 從服務(wù)器獲得數據的場(chǎng)合已經(jīng)非常少了。但是 IFrame 還有一些其它的用途。IFrame 比 XMLHttp 有優(yōu)勢的一個(gè)地方是 IFrame 可以和瀏覽器的歷史記錄結合起來(lái),而 XMLHttp 做不到這一點(diǎn)。就是說(shuō)如果數據來(lái)自于一個(gè) IFrame,以后可以使用瀏覽器的back和forward功能這樣可以帶給用戶(hù)更好的交互體驗。比如剛才我們看到的用戶(hù)搜索完 Boston,可能還想再看看 New York 的地圖,他可以簡(jiǎn)單地使用瀏覽器的 back 按鈕,而不需要重新輸入 New York 再查一遍。他如果還想看 Boston 的地圖,那么使用 forward 按鈕就可以了。
Google Maps 返回給前臺的數據為 xml 格式,由前臺的 JS 腳本解析后作相應的處理。
這里有這樣一個(gè) xml 文件的例子。在這里面實(shí)際上只有 center 和 span 是必須的??蛻?hù)端的腳本通過(guò)中心點(diǎn)位置和地圖跨度自動(dòng)像服務(wù)器請求相應的圖片。
<?xml version="1.0"?>
<page>
<center lat="49.29" lng="-123.12"/>
<span lat="0.017998" lng="0.027586"/>
</page>
以上就是 Google Maps 主要的功能。我這里主要從客戶(hù)端的角度來(lái)介紹,服務(wù)器端所提供的功能并未涉及。服務(wù)器端主要的作用是存儲數據。按照目前 15 個(gè)縮放級別,每個(gè)級別都要保留大量的貼圖文件,有人計算過(guò),即使鄉村、荒地的很多地方不需要地圖,可以使用透明圖片代替,北美地區總共的數據量大約在幾十太的級別。Google 有世界上最強大的廉價(jià) PC 服務(wù)器構成的 Linux 集群。存儲這些數據并且提供良好的性能是完全沒(méi)有問(wèn)題的。
其它的公司和個(gè)人是否可以使用 Google Maps 的技術(shù)?
其它的公司和個(gè)人完全可以使用 Google Maps 的服務(wù)。目前 Google 尚未對這一服務(wù)進(jìn)行收費。因此你可以從 Google 的服務(wù)器上請求圖片,通過(guò)在你自己的服務(wù)器顯示給客戶(hù)。剛才我做的演示完全是在本地運行的,所有的 xml 數據和 js 腳本全部都在本地,僅僅是貼圖來(lái)自于 Google 的服務(wù)器。Google 的 JS 腳本是有版權的,我這里僅僅是出于研究的目的,把腳本下載到本地,做了一些修改以便于研究。對于商業(yè)應用,可能不能這樣做,可以在頁(yè)面中直接使用 Google 服務(wù)器上的腳本。因此使用 Google Maps 的方式就是在你自己的服務(wù)器上面生成定制的地圖數據,通過(guò) XMLHttp 請求到客戶(hù)端,使用 Google Maps 的腳本解析,然后從 Google 請求貼圖數據。除了你自己的地圖數據外,還可以從其它服務(wù)器上獲得地圖數據,例如從 Google 的服務(wù)器上獲得數據。不過(guò)因為 XMLHttp 只能從本域獲得數據,為了獲得來(lái)自其它域的數據,需要在服務(wù)器端用 Servlet 實(shí)現一個(gè)代理,這個(gè) Servlet 從其它域得到地圖數據后返回給客戶(hù)端。這樣一個(gè) Servlet 寫(xiě)起來(lái)是非常簡(jiǎn)單的,只需要幾行代碼。同時(shí)在客戶(hù)端需要對 XMLHttp 對象做一個(gè)包裝,使得新的對象可以請求來(lái)自不同域的數據。
Google Maps 可以定制,Google 為定制 Maps 服務(wù)提供了很多的便利。定制的方法就是提供自己定義的地圖數據文件,在剛才這個(gè)文件中,overlay 中就是開(kāi)發(fā)者定制的內容。其中定制了兩個(gè)點(diǎn),當用戶(hù)點(diǎn)這兩個(gè)點(diǎn)的時(shí)候,會(huì )出現這兩個(gè)地點(diǎn)的說(shuō)明文字。說(shuō)明文字的產(chǎn)生使用了 XSLT 技術(shù)。例如我制作一個(gè)全部 New York 市的中餐館地圖,我可以把每個(gè)餐館的電話(huà)號碼、聯(lián)系人姓名等等信息加在上面。Google Maps 把這些接口提供出來(lái)允許開(kāi)發(fā)者與他們與他們合作,開(kāi)發(fā)出來(lái)面向不同領(lǐng)域和群體的地圖服務(wù)來(lái)。通過(guò)出讓一部分利潤來(lái)擴大其影響力,是精明的商業(yè)行為。
Google Maps 的突出優(yōu)點(diǎn):
1、功能完善,具有常規地圖服務(wù)所有的功能。
2、性能優(yōu)良。用戶(hù)幾乎從來(lái)不需要長(cháng)期的等待。
3、支持多種瀏覽器,目前 Google Maps 支持的瀏覽器包括以下這些:
IE 5.5+ (Windows)
Firefox 0.8+ (Windows, Mac, Linux)
Safari 1.2.4+ (Mac)
Netscape 7.1+ (Windows, Mac, Linux)
Mozilla 1.4+ (Windows, Mac, Linux)
Opera 7.5+ (Windows, Mac, Linux)
已經(jīng)囊括了目前所有主流的瀏覽器。
Google Maps 通過(guò)自己開(kāi)發(fā)的一套組件庫封裝了 IE 與其它瀏覽器的差別。主要的差別包括 XMLHttp、XMLDom 對象的創(chuàng )建語(yǔ)法,還有事件處理機制的不同。并且 Google Maps 盡量采用符合 Web 標準的技術(shù),使得針對不同瀏覽器開(kāi)發(fā)分支代碼的情況變得最小。
4、通過(guò)大量采用客戶(hù)端的技術(shù),放棄了傳統的基于 HTML Form 的交互模式,因此使得用戶(hù)獲得了更好的交互體驗。
5、完全的組件化和面向對象開(kāi)發(fā)。
Google Maps 組件和面向對象設計的水平是非常高的。所有主要的的控件全部封裝為對象,使用面向對象的方式進(jìn)行操作。
因為 XMLHttp 只能得到本域的數據文件,為了從其它地方獲得數據文件,可以在服務(wù)器端實(shí)現一個(gè)代理。簡(jiǎn)單而言就是實(shí)現一個(gè) Servlet,通過(guò)這個(gè) Servlet 獲得其它域的數據文件,然后返回給客戶(hù)端。
為此需要為 XMLHttp 對象做一個(gè)包裝。我們來(lái)看看具體的包裝技術(shù)。
我對于 Google Maps 客戶(hù)端腳本的整理工作目前還沒(méi)有完全結束,因此今天具體的代碼講得比較少。主要是先從大的方面介紹了 Google Maps 的功能和采用的核心技術(shù)。下次有機會(huì )了我在給大家詳細剖析一下 Google Maps 前臺的代碼。當然這需要大家對于 XHTML/CSS/JavaScript/XSLT/XMLHttp 等技術(shù)都有相當的了解才行。
今天我首先給大家介紹了 Ajax 的由來(lái)和內涵。然后通過(guò) Google Maps 作為實(shí)例讓大家充分感受到了 Ajax 技術(shù)的優(yōu)勢。目前 Ajax 已經(jīng)有越來(lái)越流行,并且進(jìn)入了主流 J2EE 開(kāi)發(fā)的領(lǐng)域。不光是小公司對 Ajax 感興趣,大公司也越來(lái)越對 Ajax 產(chǎn)生了興趣。前天我的一位在 Oracle 做開(kāi)發(fā)的朋友說(shuō)他們公司現在對 Ajax 也非常感興趣,正在組織相關(guān)知識的學(xué)習。并且會(huì )考慮建造自己的 Ajax 組件庫和開(kāi)發(fā)工具。他們公司以前使用 Applet 做過(guò)很多應用,但是 Applet 顯然已經(jīng)是很落伍的技術(shù),將來(lái)肯定會(huì )被 Java Web Start 所代替。而 JWS 也存在著(zhù)一些問(wèn)題。因此我認為 Ajax 對于他們應該來(lái)說(shuō)是一個(gè)更好的選擇。
雖然我做過(guò)很多 JavaScript 開(kāi)發(fā),非常喜歡這門(mén)語(yǔ)言。但是無(wú)庸諱言,JavaScript 目前還存在著(zhù)一些問(wèn)題,妨礙了大規模的組件化開(kāi)發(fā)。主要的問(wèn)題目前我認為有以下兩個(gè):
1、JavaScirpt 沒(méi)有 Java 那樣的 package 或者 C# 的 namespace 的概念,因此類(lèi)和函數非常容易重名。這個(gè)問(wèn)題不能僅僅通過(guò)制定命名規范來(lái)解決。
2、JavaScirpt 中的繼承不是真正的繼承,僅僅是所有的子類(lèi)對象共享一個(gè)父類(lèi)對象,這個(gè)父類(lèi)對象相當于一個(gè) Singleton,因此必須是無(wú)狀態(tài)的,不能保留自己的屬性。這個(gè)問(wèn)題使得 JavaScript 難以支持多層繼承,無(wú)法構造大的繼承體系。
目前 ECMAScript4 正在開(kāi)發(fā),其中一個(gè)主要的目標就是為 JavaScript 提供真正的面向對象編程能力。這個(gè)標準推出,到主要的瀏覽器支持這個(gè)標準還有相當長(cháng)的時(shí)間。在目前階段解決這兩個(gè)問(wèn)題有一些臨時(shí)的解決方案,由于時(shí)間原因我就不仔細講了。好在目前客戶(hù)端組件開(kāi)發(fā)的規模比起服務(wù)器端還是要小得多,所以 JavaScript 目前的能力在大部分場(chǎng)合下都是夠用了。
由于目前各種主流瀏覽器都可以很好地支持 Web 標準。這里我說(shuō)的 Web 標準指的是 XHTML/CSS/ECMAScript/DOM/XSLT 這些技術(shù)。XMLHttp 將來(lái)的一天也會(huì )擠進(jìn)標準的行列,目前對 XMLHttp 標準化的工作正在進(jìn)行中?,F在基于 Web 標準做開(kāi)發(fā)已經(jīng)成為 Web 表示層開(kāi)發(fā)的主流思想,徹底摒棄使用私有技術(shù),只為某種瀏覽器做開(kāi)發(fā)的時(shí)機已經(jīng)成熟。我并不是一個(gè)唯標準論者,我從來(lái)都是從注重實(shí)用的開(kāi)發(fā)者的角度來(lái)考慮問(wèn)題的。我也在以前也曾經(jīng)只為 IE 一種瀏覽器來(lái)做開(kāi)發(fā)。但是今天,在我發(fā)現了基于標準開(kāi)發(fā)并不會(huì )帶來(lái)額外的成本(已經(jīng)幾乎不再需要寫(xiě)針對不同瀏覽器的代碼分之),并且會(huì )帶來(lái)向后兼容的巨大價(jià)值的時(shí)候,我毫不猶豫地擁抱了 Web 標準。我也推薦大家以后盡量采用符合標準的方式來(lái)做開(kāi)發(fā),其中遇到的具體困難可以直接和我聯(lián)系。我一定會(huì )貢獻出自己的經(jīng)驗的。關(guān)于什么是符合標準的開(kāi)發(fā)方式,最佳實(shí)踐,在以后的活動(dòng)中我們可以繼續來(lái)探討。
今天我要講的內容就是這些,對于 Google Maps 感興趣的朋友可以和我直接取得聯(lián)系。我整理過(guò)的 Google Maps 的源代碼在適當的時(shí)候也會(huì )公布出來(lái)。謝謝大家今天的參與!