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

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

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

    posts - 49,comments - 97,trackbacks - 0

    Ajax 為更好的 Web 應(yīng)用程序鋪平了道路

    在 Web 應(yīng)用程序開發(fā)中,頁(yè)面重載循環(huán)是最大的一個(gè)使用障礙,對(duì)于 Java? 開發(fā)人員來(lái)說(shuō)也是一個(gè)嚴(yán)峻的挑戰(zhàn)。在這個(gè)系列中,作者 Philip McCarthy 介紹了一種創(chuàng)建動(dòng)態(tài)應(yīng)用程序體驗(yàn)的開創(chuàng)性方式。Ajax(異步 JavaScript 和 XML)是一種編程技術(shù),它允許為基于 Java 的 Web 應(yīng)用程序把 Java 技術(shù)、XML 和 JavaScript 組合起來(lái),從而打破頁(yè)面重載的范式。

    Ajax(即異步 JavaScript 和 XML)是一種 Web 應(yīng)用程序開發(fā)的手段,它采用客戶端腳本與 Web 服務(wù)器交換數(shù)據(jù)。所以,不必采用會(huì)中斷交互的完整頁(yè)面刷新,就可以動(dòng)態(tài)地更新 Web 頁(yè)面。使用 Ajax,可以創(chuàng)建更加豐富、更加動(dòng)態(tài)的 Web 應(yīng)用程序用戶界面,其即時(shí)性與可用性甚至能夠接近本機(jī)桌面應(yīng)用程序。

    Ajax 不是一項(xiàng)技術(shù),而更像是一個(gè) 模式 —— 一種識(shí)別和描述有用的設(shè)計(jì)技術(shù)的方式。Ajax 是新穎的,因?yàn)樵S多開發(fā)人員才剛剛開始知道它,但是所有實(shí)現(xiàn) Ajax 應(yīng)用程序的組件都已經(jīng)存在若干年了。它目前受到重視是因?yàn)樵?2004 和 2005 年出現(xiàn)了一些基于 Ajax 技術(shù)的非常棒的動(dòng)態(tài) Web UI,最著名的就是 Google 的 GMail 和 Maps 應(yīng)用程序,以及照片共享站點(diǎn) Flickr。這些用戶界面具有足夠的開創(chuàng)性,有些開發(fā)人員稱之為“Web 2.0”,因此對(duì) Ajax 應(yīng)用程序的興趣飛速上升。

    在這個(gè)系列中,我將提供使用 Ajax 開發(fā)應(yīng)用程序需要的全部工具 。在第一篇文章中,我將解釋 Ajax 背后的概念,演示為基于 Java 的 Web 應(yīng)用程序創(chuàng)建 Ajax 界面的基本步驟。我將使用代碼示例演示讓 Ajax 應(yīng)用程序如此動(dòng)態(tài)的服務(wù)器端 Java 代碼和客戶端 JavaScript。最后,我將指出 Ajax 方式的一些不足,以及在創(chuàng)建 Ajax 應(yīng)用程序時(shí)應(yīng)當(dāng)考慮的一些更廣的可用性和訪問(wèn)性問(wèn)題。

    更好的購(gòu)物車

    可以用 Ajax 增強(qiáng)傳統(tǒng)的 Web 應(yīng)用程序,通過(guò)消除頁(yè)面裝入從而簡(jiǎn)化交互。為了演示這一點(diǎn),我采用一個(gè)簡(jiǎn)單的購(gòu)物車示例,在向里面添加項(xiàng)目時(shí),它會(huì)動(dòng)態(tài)更新。這項(xiàng)技術(shù)如果整合到在線商店,那么用戶可以持續(xù)地瀏覽和向購(gòu)物車中添加項(xiàng)目,而不必在每次點(diǎn)擊之后都等候完整的頁(yè)面更新。雖然這篇文章中的有些代碼特定于購(gòu)物車示例,但是演示的技術(shù)可以應(yīng)用于任何 Ajax 應(yīng)用程序。清單 1 顯示了購(gòu)物車示例使用的有關(guān) HTML 代碼,整篇文章中都會(huì)使用這個(gè) HTML。


    清單1. 購(gòu)物車示例的有關(guān)片斷
    
    <!-- Table of products from store's catalog, one row per item -->
    <th>Name</th> <th>Description</th> <th>Price</th> <th></th>
    ...
    <tr>
      <!-- Item details -->
      <td>Hat</td> <td>Stylish bowler hat</td> <td>$19.99</td>
      <td>
        <!-- Click button to add item to cart via Ajax request -->
        <button onclick="addToCart('hat001')">Add to Cart</button>
      </td>
    </tr>
    ...
    
    <!-- Representation of shopping cart, updated asynchronously -->
    <ul id="cart-contents">
    
      <!-- List-items will be added here for each item in the cart -->
      
    </ul>
    
    <!-- Total cost of items in cart displayed inside span element -->
    Total cost: <span id="total">$0.00</span>
    

    Ajax 往返過(guò)程

    Ajax 交互開始于叫作 XMLHttpRequest 的 JavaScript 對(duì)象。顧名思義,它允許客戶端腳本執(zhí)行 HTTP 請(qǐng)求,并解析 XML 服務(wù)器響應(yīng)。Ajax 往返過(guò)程的第一步是創(chuàng)建 XMLHttpRequest 的實(shí)例。在 XMLHttpRequest 對(duì)象上設(shè)置請(qǐng)求使用的 HTTP 方法(GETPOST)以及目標(biāo) URL。

    現(xiàn)在,您還記得 Ajax 的第一個(gè) a 是代表 異步(asynchronous) 嗎?在發(fā)送 HTTP 請(qǐng)求時(shí),不想讓瀏覽器掛著等候服務(wù)器響應(yīng)。相反,您想讓瀏覽器繼續(xù)對(duì)用戶與頁(yè)面的交互進(jìn)行響應(yīng),并在服務(wù)器響應(yīng)到達(dá)時(shí)再進(jìn)行處理。為了實(shí)現(xiàn)這個(gè)要求,可以在 XMLHttpRequest 上注冊(cè)一個(gè)回調(diào)函數(shù),然后異步地分派 XMLHttpRequest。然后控制就會(huì)返回瀏覽器,當(dāng)服務(wù)器響應(yīng)到達(dá)時(shí),會(huì)調(diào)用回調(diào)函數(shù)。

    在 Java Web 服務(wù)器上,請(qǐng)求同其他 HttpServletRequest 一樣到達(dá)。在解析了請(qǐng)求參數(shù)之后,servlet 調(diào)用必要的應(yīng)用程序邏輯,把響應(yīng)序列化成 XML,并把 XML 寫入 HttpServletResponse

    回到客戶端時(shí),現(xiàn)在調(diào)用注冊(cè)在 XMLHttpRequest 上的回調(diào)函數(shù),處理服務(wù)器返回的 XML 文檔。最后,根據(jù)服務(wù)器返回的數(shù)據(jù),用 JavaScript 操縱頁(yè)面的 HTML DOM,把用戶界面更新。圖 1 是 Ajax 往返過(guò)程的順序圖。

    現(xiàn)在您對(duì) Ajax 往返過(guò)程有了一個(gè)高層面的認(rèn)識(shí)。下面我將放大其中的每一步驟,進(jìn)行更詳細(xì)的觀察。如果過(guò)程中迷了路,請(qǐng)回頭看圖 1 —— 由于 Ajax 方式的異步性質(zhì),所以順序并非十分簡(jiǎn)單。

    分派 XMLHttpRequest

    我將從 Ajax 序列的起點(diǎn)開始:創(chuàng)建和分派來(lái)自瀏覽器的 XMLHttpRequest。不幸的是,不同的瀏覽器創(chuàng)建 XMLHttpRequest 的方法各不相同。清單 2 的 JavaScript 函數(shù)消除了這些依賴于瀏覽器的技巧,它可以檢測(cè)當(dāng)前瀏覽器要使用的正確方式,并返回一個(gè)可以使用的 XMLHttpRequest。最好是把它當(dāng)作輔助代碼:只要把它拷貝到 JavaScript 庫(kù),并在需要 XMLHttpRequest 的時(shí)候使用它就可以了。


    清單 2. 創(chuàng)建跨瀏覽器的 XMLHttpRequest
    
    /*
     * Returns a new XMLHttpRequest object, or false if this browser
     * doesn't support it
     */
    function newXMLHttpRequest() {
    
      var xmlreq = false;
    
      if (window.XMLHttpRequest) {
    
        // Create XMLHttpRequest object in non-Microsoft browsers
        xmlreq = new XMLHttpRequest();
    
      } else if (window.ActiveXObject) {
    
        // Create XMLHttpRequest via MS ActiveX
        try {
          // Try to create XMLHttpRequest in later versions
          // of Internet Explorer
    
          xmlreq = new ActiveXObject("Msxml2.XMLHTTP");
    
        } catch (e1) {
    
          // Failed to create required ActiveXObject
    
          try {
            // Try version supported by older versions
            // of Internet Explorer
    
            xmlreq = new ActiveXObject("Microsoft.XMLHTTP");
    
          } catch (e2) {
    
            // Unable to create an XMLHttpRequest with ActiveX
          }
        }
      }
    
      return xmlreq;
    }
      

    稍后我將討論處理那些不支持 XMLHttpRequest 的瀏覽器的技術(shù)。目前,示例假設(shè)清單 2 的 newXMLHttpRequest 函數(shù)總能返回 XMLHttpRequest 實(shí)例。

    返回示例的購(gòu)物車場(chǎng)景,我想要當(dāng)用戶在目錄項(xiàng)目上點(diǎn)擊 Add to Cart 時(shí)啟動(dòng) Ajax 交互。名為 addToCart()onclick 處理函數(shù)負(fù)責(zé)通過(guò) Ajax 調(diào)用來(lái)更新購(gòu)物車的狀態(tài)(請(qǐng)參閱 清單 1)。正如清單 3 所示,addToCart() 需要做的第一件事是通過(guò)調(diào)用清單 2 的 newXMLHttpRequest() 函數(shù)得到 XMLHttpRequest 對(duì)象。接下來(lái),它注冊(cè)一個(gè)回調(diào)函數(shù),用來(lái)接收服務(wù)器響應(yīng)(我稍后再詳細(xì)解釋這一步;請(qǐng)參閱 清單 6)。

    因?yàn)檎?qǐng)求會(huì)修改服務(wù)器上的狀態(tài),所以我將用 HTTP POST 做這個(gè)工作。通過(guò) POST 發(fā)送數(shù)據(jù)要求三個(gè)步驟。第一,需要打開與要通信的服務(wù)器資源的 POST 連接 —— 在這個(gè)示例中,服務(wù)器資源是一個(gè)映射到 URL cart.do 的 servlet。然后,我在 XMLHttpRequest 上設(shè)置一個(gè)頭,指明請(qǐng)求的內(nèi)容是表單 編碼的數(shù)據(jù)。最后,我用表單編碼的數(shù)據(jù)作為請(qǐng)求體發(fā)送請(qǐng)求。

    清單 3 把這些步驟放在了一起。


    清單 3. 分派 Add to Cart XMLHttpRequest
    
    /*
     * Adds an item, identified by its product code, to the shopping cart
     * itemCode - product code of the item to add.
     */
    function addToCart(itemCode) {
    
      // Obtain an XMLHttpRequest instance
      var req = newXMLHttpRequest();
    
      // Set the handler function to receive callback notifications
      // from the request object
      var handlerFunction = getReadyStateHandler(req, updateCart);
      req.onreadystatechange = handlerFunction;
      
      // Open an HTTP POST connection to the shopping cart servlet.
      // Third parameter specifies request is asynchronous.
      req.open("POST", "cart.do", true);
    
      // Specify that the body of the request contains form data
      req.setRequestHeader("Content-Type", 
                           "application/x-www-form-urlencoded");
    
      // Send form encoded data stating that I want to add the 
      // specified item to the cart.
      req.send("action=add&item="+itemCode);
    }
    

    這就是建立 Ajax 往返過(guò)程的第一部分,即創(chuàng)建和分派來(lái)自客戶機(jī)的 HTTP 請(qǐng)求。接下來(lái)是用來(lái)處理請(qǐng)求的 Java servlet 代碼。

    servlet 請(qǐng)求處理

    用 servlet 處理 XMLHttpRequest,與處理普通的瀏覽器 HTTP 請(qǐng)求一樣。可以用 HttpServletRequest.getParameter() 得到在 POST 請(qǐng)求體中發(fā)送的表單編碼數(shù)據(jù)。Ajax 請(qǐng)求被放進(jìn)與來(lái)自應(yīng)用程序的常規(guī) Web 請(qǐng)求一樣的 HttpSession 中。對(duì)于示例購(gòu)物車場(chǎng)景來(lái)說(shuō),這很有用,因?yàn)檫@讓我可以把購(gòu)物車狀態(tài)封裝在 JavaBean 中,并在請(qǐng)求之間在會(huì)話中維持這個(gè)狀態(tài)。

    清單 4 是處理 Ajax 請(qǐng)求、更新購(gòu)物車的簡(jiǎn)單 servlet 的一部分。Cart bean 是從用戶會(huì)話中獲得的,并根據(jù)請(qǐng)求參數(shù)更新它的狀態(tài)。然后 Cart 被序列化成 XML,XML 又被寫入 ServletResponse。重要的是把響應(yīng)的內(nèi)容類型設(shè)置為 application/xml,否則 XMLHttpRequest 不會(huì)把響應(yīng)內(nèi)容解析成 XML DOM。


    清單 4. 處理 Ajax 請(qǐng)求的 servlet 代碼
    
    public void doPost(HttpServletRequest req, HttpServletResponse res)
                            throws java.io.IOException {
    
      Cart cart = getCartFromSession(req);
    
      String action = req.getParameter("action");
      String item = req.getParameter("item");
      
      if ((action != null)&&(item != null)) {
    
        // Add or remove items from the Cart
        if ("add".equals(action)) {
          cart.addItem(item);
    
        } else if ("remove".equals(action)) {
          cart.removeItems(item);
    
        }
      }
    
      // Serialize the Cart's state to XML
      String cartXml = cart.toXml();
    
      // Write XML to response.
      res.setContentType("application/xml");
      res.getWriter().write(cartXml);
    }
    

    清單 5 顯示了 Cart.toXml() 方法生成的示例 XML。它很簡(jiǎn)單。請(qǐng)注意 cart 元素的 generated 屬性,它是 System.currentTimeMillis() 生成的一個(gè)時(shí)間戳。


    清單 5. Cart 對(duì)象的XML 序列化示例
    
    <?xml version="1.0"?>
    <cart generated="1123969988414" total="$171.95">
      <item code="hat001">
        <name>Hat</name>
        <quantity>2</quantity>
      </item>
      <item code="cha001">
        <name>Chair</name>
        <quantity>1</quantity>
      </item>
      <item code="dog001">
        <name>Dog</name>
        <quantity>1</quantity>
      </item>
    </cart>
    

    如果查看應(yīng)用程序源代碼(可以從下載一節(jié)得到)中的 Cart.java,可以看到生成 XML 的方式只是把字符串添加在一起。雖然對(duì)這個(gè)示例來(lái)說(shuō)足夠了,但是對(duì)于從 Java 代碼生成 XML 來(lái)說(shuō)則是最差的方式。我將在這個(gè)系列的下一期中介紹一些更好的方式。

    現(xiàn)在您已經(jīng)知道了 CartServlet 響應(yīng) XMLHttpRequest 的方式。下一件事就是返回客戶端,查看如何用 XML 響應(yīng)更新頁(yè)面狀態(tài)。

    用 JavaScript 進(jìn)行響應(yīng)處理

    XMLHttpRequestreadyState 屬性是一個(gè)數(shù)值,它指出請(qǐng)求生命周期的狀態(tài)。它從 0(代表“未初始化”)變化到 4(代表“完成”)。每次 readyState 變化時(shí),readystatechange 事件就觸發(fā),由 onreadystatechange 屬性指定的事件處理函數(shù)就被調(diào)用。

    清單 3中已經(jīng)看到了如何調(diào)用 getReadyStateHandler() 函數(shù)創(chuàng)建事件處理函數(shù)。然后把這個(gè)事件處理函數(shù)分配給 onreadystatechange 屬性。getReadyStateHandler() 利用了這樣一個(gè)事實(shí):函數(shù)是 JavaScript 中的一級(jí)對(duì)象。這意味著函數(shù)可以是其他函數(shù)的參數(shù),也可以創(chuàng)建和返回其他函數(shù)。getReadyStateHandler() 的工作是返回一個(gè)函數(shù),檢查 XMLHttpRequest 是否已經(jīng)完成,并把 XML 響應(yīng)傳遞給調(diào)用者指定的事件處理函數(shù)。清單 6 是 getReadyStateHandler() 的代碼。


    清單 6. getReadyStateHandler() 函數(shù)
    
    /*
     * Returns a function that waits for the specified XMLHttpRequest
     * to complete, then passes its XML response to the given handler function.
     * req - The XMLHttpRequest whose state is changing
     * responseXmlHandler - Function to pass the XML response to
     */
    function getReadyStateHandler(req, responseXmlHandler) {
    
      // Return an anonymous function that listens to the 
      // XMLHttpRequest instance
      return function () {
    
        // If the request's status is "complete"
        if (req.readyState == 4) {
          
          // Check that a successful server response was received
          if (req.status == 200) {
    
            // Pass the XML payload of the response to the 
            // handler function
            responseXmlHandler(req.responseXML);
    
          } else {
    
            // An HTTP problem has occurred
            alert("HTTP error: "+req.status);
          }
        }
      }
    }
    

    HTTP 狀態(tài)碼

    在清單 6 中,檢查 XMLHttpRequeststatus 屬性以查看請(qǐng)求是否成功完成。status 包含服務(wù)器響應(yīng)的 HTTP 狀態(tài)碼。在執(zhí)行簡(jiǎn)單的 GETPOST 請(qǐng)求時(shí),可以假設(shè)任何大于 200 (OK)的碼都是錯(cuò)誤。如果服務(wù)器發(fā)送重定向響應(yīng)(例如 301 或 302),瀏覽器會(huì)透明地進(jìn)行重定向并從新的位置獲取資源;XMLHttpRequest 看不到重定向狀態(tài)碼。而且,瀏覽器會(huì)自動(dòng)添加 Cache-Control: no-cache 頭到所有 XMLHttpRequest,這樣客戶代碼永遠(yuǎn)也不用處理 304(未經(jīng)修改)服務(wù)器響應(yīng)。

    關(guān)于 getReadyStateHandler()

    getReadyStateHandler() 是段相對(duì)復(fù)雜的代碼,特別是如果您不習(xí)慣閱讀 JavaScript 的話。但是通過(guò)把這個(gè)函數(shù)放在 JavaScript 庫(kù)中,就可以處理 Ajax 服務(wù)器響應(yīng),而不必處理 XMLHttpRequest 的內(nèi)部細(xì)節(jié)。重要的是要理解如何在自己的代碼中使用 getReadyStateHandler()。

    清單 3中看到了 getReadyStateHandler() 像這樣被調(diào)用:handlerFunction = getReadyStateHandler(req, updateCart)。在這個(gè)示例中,getReadyStateHandler() 返回的函數(shù)將檢查在 req 變量中的 XMLHttpRequest 是否已經(jīng)完成,然后用響應(yīng)的 XML 調(diào)用名為 updateCart 的函數(shù)。

    提取購(gòu)物車數(shù)據(jù)

    清單 7 是 updateCart() 本身的代碼。函數(shù)用 DOM 調(diào)用檢查購(gòu)物車的 XML 文檔,然后更新 Web 頁(yè)面(請(qǐng)參閱 清單 1),反映新的購(gòu)物車內(nèi)容。這里的重點(diǎn)是用來(lái)從 XML DOM 提取數(shù)據(jù)的調(diào)用。cart 元素的 generated 屬性是在 Cart 序列化為 XML 時(shí)生成的一個(gè)時(shí)間戳,檢查它可以保證新的購(gòu)物車數(shù)據(jù)不會(huì)被舊的數(shù)據(jù)覆蓋。Ajax 請(qǐng)求天生是異步的,所以這個(gè)檢查可以處理服務(wù)器響應(yīng)未按次序到達(dá)的情況。


    清單 7. 更新頁(yè)面,反映購(gòu)物車的 XML 文檔
    
    function updateCart(cartXML) {
    
     // Get the root "cart" element from the document
     var cart = cartXML.getElementsByTagName("cart")[0];
    
     // Check that a more recent cart document hasn't been processed
     // already
     var generated = cart.getAttribute("generated");
     if (generated > lastCartUpdate) {
       lastCartUpdate = generated;
    
       // Clear the HTML list used to display the cart contents
       var contents = document.getElementById("cart-contents");
       contents.innerHTML = "";
    
       // Loop over the items in the cart
       var items = cart.getElementsByTagName("item");
       for (var I = 0 ; I < items.length ; I++) {
    
         var item = items[I];
    
         // Extract the text nodes from the name and quantity elements
         var name = item.getElementsByTagName("name")[0]
                                                   .firstChild.nodeValue;
                                                   
         var quantity = item.getElementsByTagName("quantity")[0]
                                                   .firstChild.nodeValue;
    
         // Create and add a list item HTML element for this cart item
         var li = document.createElement("li");
         li.appendChild(document.createTextNode(name+" x "+quantity));
         contents.appendChild(li);
       }
     }
    
     // Update the cart's total using the value from the cart document
     document.getElementById("total").innerHTML = 
                                              cart.getAttribute("total");
    }
    

    到此,整個(gè) Ajax 往返過(guò)程完成了,但是您可能想讓 Web 應(yīng)用程序運(yùn)行一下查看實(shí)際效果(請(qǐng)參閱 下載 一節(jié))。這個(gè)示例非常簡(jiǎn)單,有很多需要改進(jìn)之處。例如,我包含了從購(gòu)物車中清除項(xiàng)目的服務(wù)器端代碼,但是無(wú)法從 UI 訪問(wèn)它。作為一個(gè)好的練習(xí),請(qǐng)?jiān)囍趹?yīng)用程序現(xiàn)有的 JavaScript 代碼之上構(gòu)建出能夠?qū)崿F(xiàn)這個(gè)功能的代碼。

    使用 Ajax 的挑戰(zhàn)

    就像任何技術(shù)一樣,使用 Ajax 也有許多出錯(cuò)的可能性。我目前在這里討論的問(wèn)題還缺乏容易的解決方案,但是會(huì)隨著 Ajax 的成熟而改進(jìn)。隨著開發(fā)人員社區(qū)增加開發(fā) Ajax 應(yīng)用程序的經(jīng)驗(yàn),將會(huì)記錄下最佳實(shí)踐和指南。

    XMLHttpRequest 的可用性

    Ajax 開發(fā)人員面臨的一個(gè)最大問(wèn)題是:在沒有 XMLHttpRequest 可用時(shí)該如何響應(yīng)?雖然主要的現(xiàn)代瀏覽器都支持 XMLHttpRequest,但仍然有少數(shù)用戶的瀏覽器不支持,或者瀏覽器的安全設(shè)置阻止使用 XMLHttpRequest。如果開發(fā)的 Web 應(yīng)用程序要部署在企業(yè)內(nèi)部網(wǎng),那么可能擁有指定支持哪種瀏覽器的權(quán)力,從而可以認(rèn)為 XMLHttpRequest 總能使用。但是,如果要部署在公共 Web 上,那么就必須當(dāng)心,如果假設(shè) XMLHttpRequest 可用,那么就可能會(huì)阻止那些使用舊的瀏覽器、殘疾人專用瀏覽器和手持設(shè)備上的輕量級(jí)瀏覽器的用戶使用您的應(yīng)用程序。

    所以,您應(yīng)當(dāng)努力讓應(yīng)用程序“平穩(wěn)降級(jí)”,在沒有 XMLHttpRequest 支持的瀏覽器中也能夠工作。在購(gòu)物車的示例中,把應(yīng)用程序降級(jí)的最好方式可能是讓 Add to Cart 按鈕執(zhí)行一個(gè)常規(guī)的表單提交,刷新頁(yè)面來(lái)反映購(gòu)物車更新后的狀態(tài)。Ajax 的行為應(yīng)當(dāng)在頁(yè)面裝入的時(shí)候就通過(guò) JavaScript 添加到頁(yè)面,只有在 XMLHttpRequest 可用時(shí)才把 JavaScript 事件處理函數(shù)附加到每個(gè) Add to Cart 按鈕。另一種方式是在用戶登錄時(shí)檢測(cè) XMLHttpRequest 是否可用,然后相應(yīng)地提供應(yīng)用程序的 Ajax 版本或基于表單的普通版本。

    可用性考慮

    關(guān)于 Ajax 應(yīng)用程序的某些可用性問(wèn)題比較普遍。例如,讓用戶知道他們的輸入已經(jīng)注冊(cè)了可能是重要的,因?yàn)樯陈┕鈽?biāo)和 spinning 瀏覽器的常用反饋機(jī)制“throbber”對(duì) XMLHttpRequest 不適用。一種技術(shù)是用“Now updating...”類型的信息替換 Submit 按鈕,這樣用戶在等候響應(yīng)期間就不會(huì)反復(fù)單擊按鈕了。

    另一個(gè)問(wèn)題是,用戶可能沒有注意到他們正在查看的頁(yè)面的某一部分已經(jīng)更新了。可以使用不同的可視技術(shù),把用戶的眼球帶到頁(yè)面的更新區(qū)域,從而緩解這個(gè)問(wèn)題。由 Ajax 更新頁(yè)面造成的其他問(wèn)題還包括:“破壞了”瀏覽器的后退按鈕,地址欄中的 URL 也無(wú)法反映頁(yè)面的整個(gè)狀態(tài),妨礙了設(shè)置書簽。請(qǐng)參閱 參考資料 一節(jié),獲得專門解決 Ajax 應(yīng)用程序可用性問(wèn)題的文章。

    服務(wù)器負(fù)載

    用 Ajax 實(shí)現(xiàn)代替普通的基于表單的 UI,會(huì)大大提高對(duì)服務(wù)器發(fā)出的請(qǐng)求數(shù)量。例如,一個(gè)普通的 Google Web 搜索對(duì)服務(wù)器只有一個(gè)請(qǐng)求,是在用戶提交搜索表單時(shí)出現(xiàn)的。而 Google Suggest 試圖自動(dòng)完成搜索術(shù)語(yǔ),它要在用戶輸入時(shí)向服務(wù)器發(fā)送多個(gè)請(qǐng)求。在開發(fā) Ajax 應(yīng)用程序時(shí),要注意將要發(fā)送給服務(wù)器的請(qǐng)求數(shù)量以及由此造成的服務(wù)器負(fù)荷。降低服務(wù)器負(fù)載的辦法是,在客戶機(jī)上對(duì)請(qǐng)求進(jìn)行緩沖并且緩存服務(wù)器響應(yīng)(如果可能的話)。還應(yīng)該嘗試將 Ajax Web 應(yīng)用程序設(shè)計(jì)為在客戶機(jī)上執(zhí)行盡可能多的邏輯,而不必聯(lián)絡(luò)服務(wù)器。

    處理異步

    非常重要的是,要理解無(wú)法保證 XMLHttpRequest 會(huì)按照分派它們的順序完成。實(shí)際上,應(yīng)當(dāng)假設(shè)它們不會(huì)按順序完成,并且在設(shè)計(jì)應(yīng)用程序時(shí)把這一點(diǎn)記在心上。在購(gòu)物車的示例中,使用最后更新的時(shí)間戳來(lái)確保新的購(gòu)物車數(shù)據(jù)不會(huì)被舊的數(shù)據(jù)覆蓋(請(qǐng)參閱清單 7)。這個(gè)非?;镜姆绞娇梢杂糜谫?gòu)物車場(chǎng)景,但是可能不適合其他場(chǎng)景。所以在設(shè)計(jì)時(shí)請(qǐng)考慮如何處理異步的服務(wù)器響應(yīng)。

    結(jié)束語(yǔ)

    現(xiàn)在您對(duì) Ajax 的基本原則應(yīng)當(dāng)有了很好的理解,對(duì)參與 Ajax 交互的客戶端和服務(wù)器端組件也應(yīng)當(dāng)有了初步的知識(shí)。這些是基于 Java 的 Ajax Web 應(yīng)用程序的構(gòu)造塊。另外,您應(yīng)當(dāng)理解了伴隨 Ajax 方式的一些高級(jí)設(shè)計(jì)問(wèn)題。創(chuàng)建成功的 Ajax 應(yīng)用程序要求整體考慮,從 UI 設(shè)計(jì)到 JavaScript 設(shè)計(jì),再到服務(wù)器端架構(gòu);但是您現(xiàn)在應(yīng)當(dāng)已經(jīng)武裝了考慮其他這些方面所需要的核心 Ajax 知識(shí)。

    如果使用這里演示的技術(shù)編寫大型 Ajax 應(yīng)用程序的復(fù)雜性讓您覺得恐慌,那么有好消息給您。由于 Struts、Spring 和 Hibernate 這類框架的發(fā)展把 Web 應(yīng)用程序開發(fā)從底層 Servlet API 和 JDBC 的細(xì)節(jié)中抽象出來(lái),所以正在出現(xiàn)簡(jiǎn)化 Ajax 開發(fā)的工具包。其中有些只側(cè)重于客戶端,提供了向頁(yè)面添加可視效果的簡(jiǎn)便方式,或者簡(jiǎn)化了對(duì) XMLHttpRequest 的使用。有些則走得更遠(yuǎn),提供了從服務(wù)器端代碼自動(dòng)生成 Ajax 接口的方式。這些框架替您完成了繁重的任務(wù),所以您可以采用更高級(jí)的方式進(jìn)行 Ajax 開發(fā)。我在這個(gè)系列中將研究其中的一些。

    Ajax 社區(qū)正在快速前進(jìn),所以會(huì)有大量有價(jià)值的信息涌現(xiàn)。在閱讀這個(gè)系列的下一期之前,我建議您參考 參考資料 一節(jié)中列出的文章,特別是如果您是剛接觸 Ajax 或客戶端開發(fā)的話。您還應(yīng)當(dāng)花些時(shí)間研究示例源代碼并考慮一些增強(qiáng)它的方式。

    在這個(gè)系列的下一篇文章中,我將深入討論 XMLHttpRequest API,并推薦一些從 JavaBean 方便地創(chuàng)建 XML 的方式。我還將介紹替代 XML 進(jìn)行 Ajax 數(shù)據(jù)傳遞的方式,例如 JSON(JavaScript Object Notation)輕量級(jí)數(shù)據(jù)交換格式。

    posted on 2005-10-20 18:19 閔毓 閱讀(490) 評(píng)論(0)  編輯  收藏 所屬分類: Java開發(fā)
    主站蜘蛛池模板: 国产卡二卡三卡四卡免费网址 | 亚洲国产精品自在线一区二区| 97在线线免费观看视频在线观看| 福利免费在线观看| 亚洲AV网一区二区三区 | 免费看一区二区三区四区| 国产精品亚洲综合天堂夜夜| 亚洲一级毛片视频| 亚洲AV第一页国产精品| 亚洲v国产v天堂a无码久久| 免费无码成人AV片在线在线播放| 久视频精品免费观看99| 午夜网站在线观看免费完整高清观看 | 国产视频精品免费视频| 亚洲欧美在线x视频| 国产成人亚洲精品| 亚洲最大黄色网站| 久久精品国产亚洲av麻豆小说| 国产亚洲情侣一区二区无| 亚洲av午夜成人片精品电影| 国产亚洲精品免费| 永久免费bbbbbb视频| 四虎影院免费在线播放| 女人与禽交视频免费看| 性感美女视频免费网站午夜| 毛片免费全部播放一级| 成人免费一区二区三区在线观看| 一个人看www在线高清免费看| 五月婷婷综合免费| 一本无码人妻在中文字幕免费| 亚洲视频免费在线播放| 日本片免费观看一区二区| 亚洲一区二区三区免费视频| 国产妇乱子伦视频免费| 免费国产成人高清在线观看网站| av免费不卡国产观看| 女人让男人免费桶爽30分钟| 永久黄网站色视频免费| 亚洲片国产一区一级在线观看| 亚洲欧洲中文日韩久久AV乱码| 亚洲精品一品区二品区三品区|