<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-60  評論-35  文章-15  trackbacks-0
    一. 什么是AJAX?

      這個名字代表了異步JavaScript+ XMLHTTPRequest,并且意味著你可以在基于瀏覽器的JavaScript和服務器之間建立套接字通訊。其實AJAX并不是一種新技術,而是已經成功地用于現(xiàn)代瀏覽器中的若干成功技術的可能性組合。所有的AJAX應用程序實現(xiàn)了一種“豐富的”UI——這是通過JavaScript操作HTML文檔對象模型并且經由XMLHttpRequest實現(xiàn)的精確定位的數(shù)據(jù)檢索來實現(xiàn)的。典型的示例AJAX應用程序是Google Labs( http://labs.google.com )的Google Maps和Google Suggest。這些應用程序現(xiàn)場監(jiān)視用戶輸入并且提供實時的頁面更新。最重要的是,在用戶通過地圖導航或輸入一個查找字符串的同時,這些事件不需要刷新頁面。

      事實上,支持這些令人感到驚訝的應用的技術已經出現(xiàn)一段時間了,盡管它們要求復雜的技能以及使用瀏覽器的技巧。一些專利產品就提供了相似的能力——如Macromedia Flash插件,Java Applets或.NET運行時——在達到實用上已經有一段時間了。把一種可與服務器通話的腳本組件引入到瀏覽器中的思想早在IE 5.0中就已經存在。Firefox和其它流行的瀏覽器也加入到瀏覽器大軍中并以一種內置對象形式支持XMLHTTPRequest。隨著跨平臺瀏覽器的出現(xiàn),這些技術得到了認可并在2004年3月一家稱為Adaptive Path的公司中正式提出了AJAX。

      簡而言之,由于來自于Google的支持和安裝了一點可用的瀏覽器技術,加上為了一種"更好的用戶體驗",每個人都在把客戶端技術添加到Web應用程序上。

      二. AJAX與傳統(tǒng)應用程序的區(qū)別

      一個傳統(tǒng)Web應用程序模型實際上是一種基本的事件——用戶被迫提交表單以實現(xiàn)頁面交換。也就是說,表單提交和頁面?zhèn)魉蜔o法得到保證:還有更壞的情形——用戶需要再次點擊。這與AJAX截然不同-——數(shù)據(jù)跨過線路而不是完整的HTML頁面?zhèn)鬏?。這種數(shù)據(jù)交換是經由特定的瀏覽器對象:XMLHttpRequest實現(xiàn)的;再由適當?shù)倪壿媮硖幚砻總€數(shù)據(jù)請求的結果,頁面的特定區(qū)域而不是完整的頁面被更新。結果是更快的速度,更少的擁擠和更好的信息傳送控制。

      傳統(tǒng)型"click-refresh"Web應用程序強迫用戶中斷工作過程而等待頁面的重裝。通過引入AJAX技術,一個客戶端腳本能夠異步地與服務器通話,而用戶仍能保持輸入數(shù)據(jù)。除了對用戶透明之外,這樣的異步意味著服務器可以有更多時間來處理請求。

      傳統(tǒng)Web應用程序把所有的處理代理到服務器并且強迫服務器進行狀態(tài)管理。AJAX允許靈活劃分應用程序邏輯以及客戶和服務器之間的狀態(tài)管理。這就消除了一種"click-refresh"依賴性并且提供更好的服務器可伸縮性。當該狀態(tài)存儲在客戶端,你就不必跨越服務器來維持會話或保存/結束狀態(tài)-其使用期限是由客戶端來定義的。

      三. AJAX——分布式的MVC

      盡管AJAX應用程序依靠JavaScript來實現(xiàn)描述層,然而處理能力和知識庫仍然存在于服務器上。此時,AJAX應用程序大量的與J2EE服務器通訊——把數(shù)據(jù)輸入/輸出Web服務和servlets。具有基于AJAX的描述層的J2EE應用程序和標準J2EE應用程序之間的區(qū)別首先在于,MVC是通過線路分布的。通過使用AJAX,視圖是本地的,而模型和控制器是分布式的——這使得開發(fā)者能夠靈活地決定哪些部件會是基于客戶端的。具體地說,本地視圖通過巧妙地操作HTML DOM而生成圖形;控制器局部地處理用戶輸入并且根據(jù)開發(fā)者的判斷擴展到服務器的處理——經由HTTP請求(Web服務,XML/RPC或其它)實現(xiàn);模型的遠程部分是根據(jù)客戶端需要而下載的以達到實時更新客戶端頁面;并且狀態(tài)是在客戶端收集的。

      在以后的AJAX文章中,我們將比較深入地討論這里的每一種組件并提供有關它們聯(lián)合在一起進行應用的示例?,F(xiàn)在,先不多說,讓我們詳細地分析一個簡單的AJAX示例。

      四. 郵政區(qū)號校驗和查詢

      我們將創(chuàng)建一個包含三個INPUT字段(Zip,City和 State)的HTML頁面。我們將保證,只要用戶輸入郵政區(qū)號的前三個數(shù)字,該頁面上的字段就會用第一個匹配的狀態(tài)值填充。一旦用戶輸入了所有五位郵政區(qū)號數(shù),我們將立即決定和填充相應的城市。如果郵政區(qū)號無效(在服務器的數(shù)據(jù)庫沒有找到),那么我們將把郵政區(qū)號的邊界設置為紅色。這樣的可視化線索有助于用戶并且在現(xiàn)代瀏覽器中已經成為一種標準(作為一實例,當Firefox找到一個HTML頁面中的匹配關鍵字時,它會高亮與你在瀏覽器查找域輸入的內容一致的部分)。

      讓我們首先創(chuàng)建一個簡單的包含三個INPUT字段的 HTML:zip,city和state。請注意,一旦一個字符輸入進郵政區(qū)號字段域中,即調用方法zipChanged()。JavaScript函數(shù) zipChanged()(見下)在當zip長度為3時調用函數(shù)updateState(),而在當zip長度為5時調用函數(shù)up-dateCity ()。而updateCity()和updateState()把大部分的工作代理到另一個函數(shù)ask()。

    Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()"
    style="width:60"/>
    City: <input id="city" disabled maxlength="32" style="width:160"/>
    State:<input id="state" disabled maxlength="2" style="width:30"/>
    <script src="xmlhttp.js"></script>
    <script>
    var zipField = null;
    function zipChanged(){
    zipField = document.getElementById("zipcode")
    var zip = zipField.value;
    zip.length == 3?updateState(zip):zip.length == 5?updateCity(zip):"";
    }
    function updateState(zip) {
     var stateField = document.getElementById("state");
     ask("resolveZip.jsp?lookupType=state&zip="+zip, stateField, zipField);
    }
    function updateCity(zip) {
     var cityField = document.getElementById("city");
     ask("resolveZip.jsp? lookupType=city&zip="+zip, cityField, zipField);
    }
    </script>


    ? ?函數(shù)ask()與服務器進行通訊并分配一個回調函數(shù)來處理服務器的響應(見下列代碼)。后面,我們將分析具有雙重特點的resolveZip.jsp的內容-它根據(jù)zip字段中的字符數(shù)查找city或state信息。重要的是,ask()使用了具有異步特點的XmlHttpRequest,這樣填充 state和city字段或著色zip字段邊界就可以不必減慢數(shù)據(jù)入口而得以實現(xiàn)。首先,我們調用request.open()-它用服務器打開套接字頻道,使用一個HTTP動詞(GET或POST)作為第一個參數(shù)并且以數(shù)據(jù)提供者的URL作為第二個參數(shù)。request.open()的最后一個參數(shù)被設置為true-它指示該請求的異步特性。注意,該請求還沒有被提交。隨著對request.send()的調用,開始提交-這可以為POST提供任何必要的有效載荷。在使用異步請求時,我們必須使用request.onreadystatechanged屬性來分配請求的回調函數(shù)。(如果請求是同步的話,我們應該能夠在調用request.send之后立即處理結果,但是我們也有可能阻斷用戶,直到該請求完成為止。)

    HTTPRequest = function () {
     var xmlhttp=null;
     try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
     } catch (_e) {
      try {
       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (_E) { }
     }
     if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
      try {
       xmlhttp = new XMLHttpRequest();
      } catch (e) {
       xmlhttp = false;
      }
     }
     return xmlhttp;
    }

    function ask(url, fieldToFill, lookupField) {
     var http = new HTTPRequest();
     http.open("GET", url, true);
     http.onreadystatechange = function (){ handleHttpResponse(http, fieldToFill,lookupField)};
     http.send(null);
    }

    function handleHttpResponse(http, fieldToFill, lookupField) {
     if (http.readyState == 4) {
      result = http.responseText;
      if ( -1 != result.search("null") ) {
       lookupField.style.borderColor = "red";
       fieldToFill.value = "";
      } else {
       lookupField.style.borderColor = "";
       fieldToFill.value = result;
      }
     }
    }


      為ask()所使用的HttpRequest()函數(shù)(見上)是一跨瀏覽器的XMLHTTPRequest的一個實例的構造器;稍后我們將分析它。到目前為止,請注意對于handleResponse()的調用是如何用一匿名函數(shù)包裝的-這個函數(shù)是function() {handleHttpResponse(http,fieldToFill, lookupField)}。

      該函數(shù)的代碼是動態(tài)創(chuàng)建的并且在每次我們給http.onreadstatechange屬性賦值時被編譯。結果,JavaScript創(chuàng)建一個指向上下文(所有的變量都可以存取正在結束的方法-ask())的指針。這樣以來,匿名函數(shù)和handleResponse()就能夠被保證充分存取所有的上下文宿主的變量,直至到匿名函數(shù)的參考被垃圾回收站收集為止。換句話說,無論何時我們的匿名函數(shù)被調用,它都能無縫地參考request, fieldToFill和lookupField變量,就象它們是全局的一樣。而且,每次ask()調用都將創(chuàng)建環(huán)境的一個獨立拷貝,并且此時這些變量中保存有該函數(shù)將結束時的值。

      現(xiàn)在,讓我們分析一下函數(shù)handleResponse()。既然它能夠在請求處理的不同狀態(tài)下激活,那么該函數(shù)將忽略所有的情形-除了該請求處理完成之外-這相應于request.readyState屬性等于4("Completed")。此時,該函數(shù)讀取服務器的響應文本。與它的名字所暗示的相反,XmlHttpRequest的輸入和輸出都不必限于XML格式。特別地,我們的resolveZip.jsp(見源碼中的列表1)返回普通文本。如果返回值為"unknown",那么該函數(shù)將假定郵政區(qū)號是無效的并且把查找字段(zip)邊界顏色置為紅色。否則,返回值被用于填充字段state或 city,并且zip的邊界被賦予一種缺省顏色。

    XMLHttpRequest-傳輸對象

      讓我們返回到我們的XMLHTTPRequest的跨瀏覽器實現(xiàn)。最后一個列表包含一個HttpRequest()函數(shù)-它向上兼容于IE5.0和 Mozilla 1.8/FireFox。為簡化起見,我們只創(chuàng)建一個微軟XMLHTTPRequest對象,而且如果創(chuàng)建失敗,我們假定它是 Firefox/Mozilla。

      該函數(shù)的核心是XMLHTTPRequest-這是一個本機瀏覽器對象,它為包括HTTP協(xié)議的任何東西與服務器之間的通訊提供方便。它允許指定任何 HTTP動詞,頭部和有效載荷,并且能夠以異步或同步方式工作。不需要下載也不需要安裝任何插件-盡管在IE的情形下,XMLHTTPRequest是一個集成到瀏覽器內部的ActiveX。因而,"Run ActiveX Control and Plugins"默認IE權限應該正好適合使用它。

      最重要的是,XMLHTTPRequest允許一個到服務器的RPC風格的編程查詢而不需要任何頁面刷新。它以一種可預測的,可控制的方式來實現(xiàn)此-提供了到HTTP協(xié)議的所有細節(jié)的完整存取-包括頭部和數(shù)據(jù)的任何定制格式。在以后的文章中,我們將向你展示其它一些業(yè)界協(xié)議-你可以在這些傳輸協(xié)議(如 Web服務和XML-RPC)之上運行-它們極大地簡化大規(guī)模應用程序的開發(fā)和維護。

      五.服務器端邏輯

      最后,服務器端的resolveZip.jsp被從函數(shù)ask()中調用(見所附源碼中的列表1)。這個resolveZip.jsp在兩種由當前的郵政區(qū)號長度所區(qū)分的獨立的場所下被調用(見zipChanged()函數(shù))。請求參數(shù)lookupType的值或者是state或者是city。為簡化起見,我們將假定,兩個文件state.properties和city.properties都位于服務器中C驅動器的根目錄下。 resolveZip.jsp邏輯負責用適當?shù)念A裝載的文件返回查找值。

      我們的支持AJAX的頁面現(xiàn)在已經準備好了。

      六.遠程腳本技術-一種可選方法

      一些更舊的AJAX實現(xiàn)是基于所謂的遠程腳本技術。這種思想是,用戶的行為導致經由IFRAME對服務器進行查詢,而服務器用JavaScript作出響應,該腳本一旦到達客戶端立即被執(zhí)行。這與XMLHttpRequest方法相比存在較大的區(qū)別,在后者情況下,服務器響應數(shù)據(jù)而客戶端解釋數(shù)據(jù)。其好處是這種解決方案支持更舊的瀏覽器。

      基于IFRAME示例的HTML部分(見所附源碼中的列表2)與我們在XMLHTTPRequest場合下所用的極相似,但是這次我們將引入另外一個IFRAME元素-controller:

    Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()"
    style="width:60" size="20"/>
    City: <input id="city" disabled maxlength="32" style="width:160" size="20"/>
    State:<input id="state" disabled maxlength="2" style="width:30" size="20"/>
    <iframe id="controller" style="visibility:hidden;width:0;height:0"></iframe>

      我們保持每次擊鍵都調用zipChanged()一次,但是這一次,從zipChanged()中被調用的函數(shù)ask()(見所附源碼中的列表3)負責設置IFRAME的src屬性,而不是調用一個XMLHTTPRequest:

    function ask(url, fieldToFill, lookupField){
     var controller = document.getElementById("controller");
     controller.src= url+"&field="+fieldToFill.id+"&zip="+lookupField.id;
    }

      服務器端邏輯由一個粗略的resolveZip.jsp(見所附源碼中的列表4)所描述。它與它的XMLHTTPRequest對應物相區(qū)別-它返回 JavaScript語句,這些語句設置變量字段lookup和city的全局值,而且一旦它到達瀏覽器即從全局窗口的執(zhí)行上下文中調用函數(shù) response()。

      函數(shù)response()是一修改版本的handleResponse()-這一函數(shù)可以免于處理未完成的請求(詳見本文所附源碼中的列表2)。

      七. 難題

      為簡化起見,讓我們"俯看"一下在我們的示例代碼中的一些重要的問題:

      1.事實-XMLHTTPRequest對象實例和回調函數(shù)調用在被使用以后并沒被破壞-在每次調用后這有可能導致內存泄漏。適當編寫的代碼應該破壞或重用對象池中的這些實例。而且,客戶端必須使用與服務器軟件相同的對象管理技術。

      2.在大多數(shù)情況下,錯誤往往得不到有效處理。例如,在方法ask()中對request.open()的調用可能引發(fā)一個異常,這是必須要捕獲和處理的,即使在瀏覽器中沒有設置JavaScript異常自動捕獲功能。而handleResponse()函數(shù)又是另外一個例子。它必須要為可能的服務器端和通訊錯誤而檢查headers和responseText值。在發(fā)生錯誤的情況下,它必須盡力恢復并/或者報告錯誤。正確開發(fā)的AJAX應用程序要盡可能避免"提交"松散的數(shù)據(jù),因為往往存在線路斷開和其它低級通訊的問題-所以這些程序必須建立一個強壯的和自恢復的框架為此提供支持。

      3.當前服務器端框架提供相當多的功能-它們可以與一種自由刷新方法和諧相處。例如,讓我們考慮一個定制的在指定時間內的服務器端認證的問題。在這種情況下,我們必須攔截到XMLHTTPRequest調用的安全系統(tǒng)響應,顯示登錄屏幕,然后在用戶被認證后重新發(fā)出請求。

      所有的這些問題只是一些典型的用低級API工作的任何應用程序代碼,而且所有這些問題都能被解決。好消息是,解決這些問題所需要的技術十分相似于大多數(shù)Java開發(fā)技術,如Web服務,定制標簽和XML/XSLT。唯一的區(qū)別在于,現(xiàn)在這些技術以下列形式用于客戶端:

      ·Web服務-使用SOAP/REST/RPC等簡單通訊標準

      ·客戶端定制標簽-打包豐富的客戶端控件并集成AJAX功能

      ·數(shù)據(jù)操作-基于XML和基于XSLT技術

      八. 小結

      AJAX方法能夠向人們提供一種與桌面應用程序相同的豐富的互聯(lián)網(wǎng)體驗。但是,我們必須有選擇地使用AJAX技術,如當你仍在線購物時,你絕對不想讓你的信用卡通過后臺處理就悄悄地開始付款。AJAX會成為一種持續(xù)的動力嗎?我們當然希望這樣。在過去的五年時間內我們一直在努力開發(fā)AJAX應用程序并且能證明它是健全并且很有效的。然而,它要求一個開發(fā)者必須精通大量技術而不是在傳統(tǒng)的"click-refresh"Web應用程序中所使用的那些。
    posted on 2007-01-24 12:56 Q系列類、方法、變量…… 閱讀(189) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 精品国产免费一区二区三区香蕉| 视频免费1区二区三区| 免费视频成人片在线观看| 国精无码欧精品亚洲一区| 免费夜色污私人影院网站电影| 免费永久在线观看黄网站| 国产av无码专区亚洲av毛片搜| 狠狠久久永久免费观看| 亚洲AV日韩AV一区二区三曲| 在线观看永久免费视频网站| 国产精品成人亚洲| 亚洲视频一区二区| 中文字幕不卡高清免费| 亚洲成AV人片在| 色老头永久免费网站| 亚洲精品第一综合99久久| 国产精品国产自线拍免费软件| 日本亚洲中午字幕乱码| 激情综合色五月丁香六月亚洲| a级黄色毛片免费播放视频| 久久精品国产亚洲精品2020| 日本妇人成熟免费中文字幕| 亚洲av无码专区国产不乱码| 中文亚洲成a人片在线观看| 日本免费一区二区三区| 亚洲色精品三区二区一区| 亚洲Av无码国产情品久久| 久草免费福利视频| 国产精品亚洲片夜色在线| 免费少妇a级毛片人成网| 丝袜捆绑调教视频免费区| 亚洲冬月枫中文字幕在线看| 国产免费av片在线播放| 亚洲免费观看视频| 亚洲乱码日产精品一二三| 亚洲熟妇中文字幕五十中出| 一本无码人妻在中文字幕免费 | 亚洲日韩在线观看免费视频| 久久国产乱子免费精品| 亚洲成熟丰满熟妇高潮XXXXX | 久久WWW免费人成一看片|