|
改變Web應(yīng)用的開(kāi)發(fā)方式(一) ----由Ajax引起的思考
引子 如果讓你說(shuō)出在最近在Web開(kāi)發(fā)領(lǐng)域中被炒得最火的一個(gè)詞,八九不離十將會(huì)是Ajax。套用魯迅先生說(shuō)過(guò)的一句話:“世上本沒(méi)有概念,炒的人多了,便成了概念”。其實(shí)這個(gè)概念之所以能夠被炒起來(lái),除了Google等公司給我們炫了幾個(gè)很Cool的Ajax應(yīng)用之外(Gmail, Google Suggest, Google Maps),更關(guān)鍵在于它為我們提供了一種Web開(kāi)發(fā)的新思路 (Ajax: A New Approach to Web Applications )??赐赀@篇給Ajax命名的文章,首當(dāng)其沖的是異步調(diào)用,通過(guò)XMLHttpRequest這一手段,我們可以使用戶(hù)不用在進(jìn)行每一個(gè)操作后干等Web的響應(yīng),從而提升了用戶(hù)流暢的體驗(yàn)。 這個(gè)是這篇文章的核心,也是Ajax吸引人的一個(gè)亮點(diǎn)。但是今天我們要討論的,卻是文中提出的另一張圖(圖1),雖然Jesse James Garrett沒(méi)有對(duì)其進(jìn)行詳盡的描述,但是它同樣能給我們帶來(lái)一定的思考空間。
傳統(tǒng)的Web開(kāi)發(fā)方式及其發(fā)展歷程 如圖1所示,左邊是傳統(tǒng)的Web開(kāi)發(fā)方式:Web Server接受客戶(hù)端傳送過(guò)來(lái)的HTTP請(qǐng)求,進(jìn)行解析,與后臺(tái)交互進(jìn)行業(yè)務(wù)處理,再把結(jié)果渲染成HTML,最后將其傳到瀏覽器。雖然這種方式歷經(jīng)了多年的發(fā)展,我們也有不少的開(kāi)發(fā)框架和工具可以使用,但是Web應(yīng)用的開(kāi)發(fā)仍顯得比較復(fù)雜低效。我們通過(guò)回顧Java Web開(kāi)發(fā)的發(fā)展歷程來(lái)分析一下這個(gè)問(wèn)題。 Sevlet為Java Web編程的早期規(guī)范,把Http請(qǐng)求與響應(yīng)被封裝成Java對(duì)象。在這段時(shí)期,整個(gè)Web應(yīng)用基本僅由程序員來(lái)完成,他們?cè)赟ervlet程序中從Request中取得客戶(hù)端傳送過(guò)來(lái)的參數(shù),進(jìn)行處理后將結(jié)果寫(xiě)回到Response對(duì)象的輸出流中,這種方式無(wú)論對(duì)開(kāi)發(fā)人員或是用戶(hù)來(lái)說(shuō)都是比較痛苦的,程序員需要在程序中寫(xiě)入大量重復(fù)枯燥的HTML輸出語(yǔ)句,而且這種方式也很難在HTML的美工方面做得很好,所以對(duì)于用戶(hù)來(lái)說(shuō),他們只能看到一些粗糙簡(jiǎn)陋的頁(yè)面。 為了解決這個(gè)問(wèn)題,JSP等動(dòng)態(tài)網(wǎng)頁(yè)技術(shù)出臺(tái)了,首次在頁(yè)面與程序分離方面邁出了一步,程序員可以在美工人員完成的HTML頁(yè)面中嵌入程序代碼,用來(lái)控制頁(yè)面中動(dòng)態(tài)部分。但是由于JSP規(guī)范對(duì)頁(yè)面中Java程序沒(méi)有太大的限制,對(duì)哪一些程序應(yīng)該放在動(dòng)態(tài)頁(yè)面中,哪一些程序需要放在后臺(tái)程序中處理也沒(méi)有一定的規(guī)范。導(dǎo)致了在很多的Web項(xiàng)目中,大量的Java代碼充徹于HTML Tag的字里行間,給美工與程序員都帶來(lái)了不少痛苦。 為此,Craig R. McClanahan等一些有見(jiàn)解的開(kāi)發(fā)人員開(kāi)始提出了Web開(kāi)發(fā)的model2,將經(jīng)典的MVC模式導(dǎo)入到Web開(kāi)發(fā)中,出現(xiàn)了Struts這個(gè)至今仍非常流行的Web框架,在架構(gòu)上,它把瀏覽器提交的請(qǐng)求交給一個(gè)統(tǒng)一的Servlet控制器,由控制器通過(guò)讀取控制文件將事件分配到相應(yīng)對(duì)象模型(Actions)中,實(shí)現(xiàn)了對(duì)Request事件響應(yīng)的對(duì)象封裝。而在頁(yè)面渲染方面,提供了一套與HTML形式類(lèi)似的Taglib庫(kù),意圖于減少HTML與Java程序間的異構(gòu)性,更好地實(shí)現(xiàn)頁(yè)面與邏輯分離。后來(lái)的出現(xiàn)的WebWork, Spring MVC基本上繼承了Struts中的MVC思路,只是在事件分派,頁(yè)面渲染的靈活性上進(jìn)行了提高。但是這種所謂Web MVC的方式并不能徹底解決Web開(kāi)發(fā)中的痛苦,由于Action的激活基于每一個(gè)頁(yè)面跳轉(zhuǎn)產(chǎn)生的Request請(qǐng)求,對(duì)于復(fù)雜的頁(yè)面事件交互,Action的粒度與頁(yè)面中狀態(tài)的保持都是比較麻煩的問(wèn)題。而且由于TagLib沒(méi)有一個(gè)統(tǒng)一的規(guī)范,自定義性太強(qiáng),使得嵌入它的頁(yè)面很難被主流的HTML編輯器支持,始終不能擺脫頁(yè)面與程序分離的問(wèn)題。 在基于Request,對(duì)Action進(jìn)行封裝的框架之外,還有另一個(gè)Web框架的分支,那便是JSF等以對(duì)可視化組件進(jìn)行封裝為基礎(chǔ)的架構(gòu)。它力圖將HTML元素的屬性和事件的監(jiān)聽(tīng)都封裝在后臺(tái)的對(duì)象中,為開(kāi)發(fā)者屏蔽掉處理HTTP Request/Response方式帶來(lái)的事件分派,狀態(tài)保存等麻煩。這種方式在MS的.net開(kāi)發(fā)中一直被提倡,希望Web程序的開(kāi)發(fā)能像VB中的一樣,利用強(qiáng)大的IDE,制作布局,畫(huà)出控件,為控件指定監(jiān)聽(tīng)器并書(shū)寫(xiě)響應(yīng)程序。但是這種方式也存在一定的問(wèn)題,因?yàn)锽/S的Web架構(gòu)畢竟與單機(jī)或是胖客戶(hù)端不同,如果連結(jié)到服務(wù)器的并發(fā)用戶(hù)較多時(shí),這種將組件的事件監(jiān)聽(tīng),狀態(tài)保持和渲染的工作都交由后臺(tái)程序的方式必將對(duì)服務(wù)器資源提出更大的挑戰(zhàn)。
總結(jié)以上各種Web開(kāi)發(fā)方式所面臨的問(wèn)題,其根本癥結(jié)可歸于以下三點(diǎn): 一是由于HTTP基于請(qǐng)求/響應(yīng)范式。傳統(tǒng)應(yīng)用中瀏覽器發(fā)出請(qǐng)求,服務(wù)器針對(duì)每一個(gè)請(qǐng)求返回一個(gè)HTML頁(yè)面。 二是由于HTML作為一個(gè)用于內(nèi)容布局的結(jié)構(gòu)化標(biāo)志語(yǔ)言,與進(jìn)行數(shù)據(jù)/邏輯處理的編程語(yǔ)言存在異構(gòu)性。 三是由于Web應(yīng)用以服務(wù)器為中心,Web開(kāi)發(fā)需要考慮服務(wù)器端的負(fù)載問(wèn)題。
Ajax能給我們帶來(lái)什么? 對(duì)于這三大難題,Ajax方式能給我們帶來(lái)解決的途徑嗎? 我們回頭看看圖1的右邊。與傳統(tǒng)的Web應(yīng)用開(kāi)發(fā)方式比較,它在瀏覽器端添加了一個(gè)層----Ajax engine,由用戶(hù)產(chǎn)生的頁(yè)面事件交由這個(gè)引擎處理,它負(fù)責(zé)向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器傳回的是業(yè)務(wù)數(shù)據(jù)而非HTML,引擎接受之后,進(jìn)行渲染,通過(guò)瀏覽器的解析在頁(yè)面上顯示出來(lái)。說(shuō)白了,就是將事件監(jiān)聽(tīng)與頁(yè)面渲染的工作交給了瀏覽器,而后臺(tái)服務(wù)器只負(fù)責(zé)業(yè)務(wù)邏輯的處理。 在Ajax方式下,HTTP基于請(qǐng)求/響應(yīng)的范式仍然沒(méi)有變化,但是由于有XmlHttpRequest對(duì)象(Ajax engine的核心)的支持,我們不需要像以前那樣將每一次請(qǐng)求發(fā)到服務(wù)器后,由服務(wù)器解析請(qǐng)求再進(jìn)行事件發(fā)配,之后返回刷新用的HTML頁(yè)面。在新的方式下,由于事件的監(jiān)聽(tīng)和處理在瀏覽器內(nèi)部實(shí)現(xiàn),它的反應(yīng)周期可以被縮短,事件的處理粒度可以更方便的做到更細(xì),而且由于支持異步方式發(fā)送Request請(qǐng)求和接受Response響應(yīng),用戶(hù)事件的控制有了更大的靈活性。 在Ajax方式下,HTML與程序的異構(gòu)性仍然存在。但是由于把頁(yè)面渲染放到瀏覽器中,使得我們可以通過(guò)HTML DOM對(duì)HTML的各個(gè)組件以對(duì)象的方式進(jìn)行訪問(wèn)與控制而不是刷新整個(gè)頁(yè)面,使得頁(yè)面的渲染變得更加靈活,簡(jiǎn)便,豐富多彩。想想別扭的JSP Tag或是與HTML似近實(shí)疏的TagLib,還有Velocity等模版語(yǔ)言,他們的Tag被插入到HTML原本的Tag中,指揮服務(wù)器程序?qū)Ρ凰莸腍TML進(jìn)行邏輯操作從而來(lái)達(dá)到動(dòng)態(tài)渲染頁(yè)面的目的,不可避免的存在頁(yè)面結(jié)構(gòu)與程序邏輯混雜的問(wèn)題。 在Ajax方式下,Web程序仍然以服務(wù)器為中心,但是由于事件處理與頁(yè)面渲染的工作可以由瀏覽器來(lái)?yè)?dān)當(dāng),從而減輕了服務(wù)器的負(fù)擔(dān)。
Ajax開(kāi)發(fā)方式存在的問(wèn)題 既然Ajax方式存在以上優(yōu)點(diǎn),XmlHttpRequest,HTML DOM也不是最近才浮現(xiàn)的,為何這種方式到如今才進(jìn)入我們的視野,而未能成為Web開(kāi)發(fā)的主流呢?原因有以下幾點(diǎn): 1. 它依賴(lài)于瀏覽器。而至今各不同廠商的瀏覽器,甚至同一廠商瀏覽器的不同版本,對(duì)XmlHttpRequest與HTML DOM的使用方式皆有所區(qū)別。 2. 它依賴(lài)于JavaScript。從而有帶來(lái)了以下問(wèn)題: Ø 用戶(hù)可以很方便地關(guān)掉瀏覽器的JavaScript支持。從而使Ajax無(wú)用武之地。 Ø JavaScript本身的語(yǔ)法要求過(guò)于靈活松散,降低了它的可讀性 Ø 沒(méi)有強(qiáng)大好用的IDE與Debug工具 Ø 對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),在習(xí)慣于傳統(tǒng)的Web應(yīng)用開(kāi)發(fā)之后,大部分人對(duì)其不重視,認(rèn)為它只是做頁(yè)面即時(shí)校驗(yàn)或一些頁(yè)面效果的小伎倆
問(wèn)題的解決 雖然Ajax存在著這樣的問(wèn)題,有些看起來(lái)甚至是致命的,但畢竟它還是被炒起來(lái)了,火起來(lái)了?;贏jax的網(wǎng)站春筍般涌現(xiàn),用于Ajax開(kāi)發(fā)的框架與工具也嶄露頭角(Google開(kāi)放了AjaXslt,微軟推出了Atlas,JSF中加入隊(duì)Ajax的支持)。這些都給我們一個(gè)信號(hào),會(huì)有越來(lái)越多的網(wǎng)站與應(yīng)用傾向于這種方式。為此,瀏覽器廠商會(huì)考慮到這個(gè)問(wèn)題,雖說(shuō)標(biāo)準(zhǔn)化不是一朝一夕的事情,但是大家會(huì)朝這個(gè)方向走得更近而非更遠(yuǎn)。隨著Ajax應(yīng)用越來(lái)越多的閃亮登場(chǎng),用戶(hù)關(guān)掉JavaScript的可能性進(jìn)一步降低。這是發(fā)展的趨勢(shì),但就目前的現(xiàn)狀來(lái)說(shuō),支持XmlHttpRequest, HTML DOM, JavaScript的瀏覽器也已是Web程序客戶(hù)端的最大平臺(tái),而且將各瀏覽器間使用差別封裝起來(lái)的Ajax engine也已經(jīng)出現(xiàn)。從外部環(huán)境來(lái)講,Ajax的推廣應(yīng)用已經(jīng)不成大的問(wèn)題。 剩下的就是開(kāi)發(fā)人員的問(wèn)題了。對(duì)于JavaScript,它能做到什么,能從何種程度上改變我們開(kāi)發(fā)Web應(yīng)用的方式?JavaScript有其先天不足,但是如果我們以O(shè)O的思想來(lái)看待它,利用并編寫(xiě)可重用度高的JavaScript組件,把前后臺(tái)組織成一個(gè)新的框架,你會(huì)發(fā)現(xiàn),比較起以往的方式,Web開(kāi)發(fā)確實(shí)變得簡(jiǎn)單了。我將在本文的第二篇中介紹對(duì)這樣框架的特性要求和實(shí)現(xiàn)手段。而至此,需要我們做的只是一點(diǎn):觀念的轉(zhuǎn)變。 |