Web開發-Ajax入門詳解

一個實例

在開始正式講解 Ajax之前,首先讓我們先來看看Google Map使用Ajax改善其產品設計的效果。

1. 在瀏覽器地址欄中輸入http://maps.google.com打開Google Map的界面。

2. 在頁面頂端的搜索框中輸入“China”,單擊“Search”按鈕。

3. 單擊地圖右上角的“Satellite”按鈕,切換到衛星界面。

4. 調整地圖左上角的尺寸,方法或者縮小當前區域。可以看到,地圖區域的圖象根據標尺的位置快速的變換。

5. 按住鼠標左鍵,拖拽地圖,地圖區域的圖象隨着鼠標的移動而移動這個過程的圖象是實時更新的。效果如下圖所。



 

 

 

由上可以明顯的看出,當用戶拖動地圖進行操作的時候,Web頁上的地圖立即發生相應的變化,頁面卻沒有刷新,當按住鼠標左鍵移動地圖的時候,地圖跟着移動,這個過程是快速的,而期間用戶沒有想服務器提交表單或和單擊一個超鏈接。如果用傳統的Web應用程序交互思維來理解,這個過程是難以理解的,這正是Ajax的魅力。

一、什麼是Ajax?

     在研究ajax之前首先讓我們先來討論一個問題 ——什麼是Web 2.0。聽到 Web 2.0 這個詞的時候,應該首先問一問 “Web 1.0是什麼?雖然很少聽人提到 Web 1.0,實際上它指的就是具有完全不同的請求和響應模型的傳統 Web。比如,到 hdu.edu.cn網站上點擊一個按鈕。就會對服務器發送一個請求,然後響應再返回到瀏覽器。該請求不僅僅是新內容和項目列表,而是另一個完整的 HTML頁面。因此當 Web瀏覽器用新的 HTML頁面重繪時,可能會看到閃爍或抖動。事實上,通過看到的每個新頁面可以清晰地看到請求和響應。

  Web 2.0(在很大程度上)消除了這種看得見的往復交互。比如在 Google Maps上,你可以拖動地圖,放大和縮小,只有很少的重繪操作。當然這裏仍然有請求和響應,只不過都藏到了幕後。作爲用戶,體驗更加舒適,感覺很像桌面應用程序。這種新的感受和範型就是當有人提到 Web 2.0時您所體會到的。

  需要關心的是如何使這些新的交互成爲可能。顯然,仍然需要發出請求和接收響應,但正是針對每次請求/響應交互的 HTML重繪造成了緩慢、笨拙的 Web交互的感受。因此很清楚,我們需要一種方法使發送的請求和接收的響應只 包含需要的數據而不是整個 HTML頁面。惟一需要獲得整個新 HTML頁面的時候就是希望用戶看到 新頁面的時候。

  但多數交互都是在已有頁面上增加細節、修改主體文本或者覆蓋原有數據。這些情況下,Ajax Web 2.0方法允許在不 更新整個 HTML頁面的情況下發送和接收數據。對於那些經常上網的人,這種能力可以讓您的應用程序感覺更快、響應更及時,讓他們不時地光顧您的網站。

 

因此在這裏,我們是時候可以對ajax做出一個完整的解釋了,Adaptive Path公司的Jesse James Garrett這樣定義Ajax

  Ajax不是一種技術。實際上,它由幾種蓬勃發展的技術以新的強大方式組合而成。Ajax包含:

  • 基於XHTMLCSS標準的表示;
  • 使用Document Object Model進行動態顯示和交互;
  • 使用XMLHttpRequest與服務器進行異步通信;
  • 使用JavaScript綁定一切。

這非常好,但爲什麼要以Ajax命名呢?其實術語Ajax是由Jesse James Garrett創造的,他說它是“Asynchronous JavaScript + XML的簡寫”。

二、Ajax工作原理

通過上述的定義,我們應該已經知道Ajax的組成了,即他是由XHTML,XML,CSS,DOM,XMLHttpRequest,JavaScript等技術綜合而成的,然而,真正使用Ajax能實現異步通信,要真正實現這種絢麗的奇蹟,必須非常熟悉一個JavaScript對象,即 XMLHttpRequest。因此我們要了解Ajax的工作原理,就要從理解XMLHttpRequest這個對象開始。

下面給出將要用於該對象的很少的幾個 方法和屬性。

 open():建立到服務器的新請求。

     send():向服務器發送請求。

     abort():退出當前請求。

  
  readyState:提供當前 HTML的就緒狀態。

  
  responseText:服務器返回的請求響應文本。

    onreadystatechange:回調方法

 responseXML:服務器返回的請求響應XML形式組織的文本。

 下面我們簡單的介紹一下這幾個方法的作用。

1、創建一個XMLHttpRequest

    首先需要創建一個新變量並賦給它一個 XMLHttpRequest對象實例。這在 JavaScript中很簡單,只要對該對象名使用 new關鍵字即可,如下代碼所示。

script language="javascript" type="text/javascript"
 var request = new XMLHttpRequest();
/script
  在 JavaScript中用 var創建一個變量,給它一個名字(如 “request”),然後賦給它一個新的 XMLHttpRequest實例。此後就可以在函數中使用該對象了。
錯誤處理
  在實際上各種事情都可能出錯,而上面的代碼沒有提供任何錯誤處理。較好的辦法是創建該對象,並在出現問題時優雅地退出。比如,任何較早的瀏覽器都不支持 XMLHttpRequest,您需要讓這些用戶知道有些地方出了問題。下面js代碼通過創建getXMLHttpRequest()方法說明如何創建該對象。

代碼1:一個詳細的XMLHttpRequest對象的創建

script language="javascript" type="text/javascript"

function getXMLHttpRequest(){
 var request = false;
 try {

 request = new XMLHttpRequest();
 } catch (trymicrosoft) {
  try {
   request = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (othermicrosoft) {
   try {
    request = new ActiveXObject("Microsoft.XMLHTTP");
   } catch (failed) {
    request = false;
   }
  }
 }
 return request;

}
/script
  一定要理解這些步驟:
  創建一個新變量 request並賦值 false。後面將使用 false作爲判定條件,它表示還沒有創建 XMLHttpRequest對象。
  ·增加 try/catch塊:
  ·嘗試創建 XMLHttpRequest對象。
    1、如果失敗(catch (failed))則保證 request的值仍然爲 false
    2、檢查 request是否仍爲 false(如果一切正常就不會是 false)。
  ·如果出現問題則request返回 false

此外,在上面的代碼中,我們是不是注意到了一個問題,就是當request = new XMLHttpRequest();出現異常的時候,在catch語句中我們用了request = new ActiveXObject("Msxml2.XMLHTTP");request = new ActiveXObject("Microsoft.XMLHTTP");等語句進行對象獲取,這是針對IE瀏覽器而進行的操作,因爲IE瀏覽器對 XMLHttpRequest 版本有不同的稱呼。事實上,它將其稱爲幾種 不同的東西。如果使用較新版本的 Internet Explorer,則需要使用對象 Msxml2.XMLHTTP,而較老版本的 Internet Explorer 則使用 Microsoft.XMLHTTP。我們需要支持這兩種對象類型(同時還要支持非 Microsoft瀏覽器)。

2、用XMLHttpRequest發送請求
  得到請求對象之後就可以進入請求/響應循環了。記住,XMLHttpRequest惟一的目的是讓您發送請求和接收響應。其他一切都是JavaScriptCSS或頁面中其他代碼的工作:改變用戶界面、切換圖像、解釋服務器返回的數據。準備好 XMLHttpRequest之後,就可以向服務器發送請求了。
  Ajax採用一種沙箱安全模型。因此,Ajax代碼(具體來說就是 XMLHttpRequest對象)只能對所在的同一個域發送請求。如果讓 Ajax代碼在www.hdu.edu.cn上運行,則必須 www.hdu.edu.cn中運行的腳本發送請求。
       設置服務器 URL
  首先要確定連接的服務器的 URL。這並不是 Ajax的特殊要求,但仍然是建立連接所必需的。多數應用程序中都會結合一些靜態數據和用戶處理的表單中的數據來構造該 URL。比如,下列 JavaScript代碼獲取電話號碼字段的值並用其構造 URL

代碼2: 建立請求 URL

script language="javascript" type="text/javascript"
function getCustomerInfo() {
 var phone = document.getElementById("phone").value;
 var url = "/cgi-local/lookupCustomer.jsp?phone=" + escape(phone);
}
/script
  首先,代碼創建了一個新變量 phone,並把 ID “phone”的表單字段的值賦給它。下列代碼展示了這個表單的XHTML,其中可以看到 phone字段及其 id屬性。   

代碼3 Break Neck Pizza表單

body
 <form action="POST"
  <pEnter your phone number:
   <input type="text" size="14" name="phone" id="phone" onChange="getCustomerInfo();" /
  </p
  <pYour order will be delivered to:/p
  <div id="address"></div
  <pType your order in here:/p
  <p><textarea name="order" rows="6" cols="50" id="order"></textarea></p
  <p><input type="submit" value="Order Pizza" id="submit" /></p
 </form
/body
  還要注意,當用戶輸入電話號碼或者改變電話號碼時,將觸發getCustomerInfo()方法。該方法取得電話號碼並構造存儲在 url變量中的 URL字符串。由於 Ajax代碼是沙箱型的,因而只能連接到同一個域,實際上 URL中不需要域名。該例中的腳本名爲 /cgi-local/lookupCustomer.jsp。最後,電話號碼作爲 GET參數附加到該腳本中:"phone=" + escape(phone)。 

       打開請求

有了要連接的URL後就可以配置請求了。可以用XMLHttpRequest對象的open()方法來完成。該方法有五個參數:
   ·request-type :發送請求的類型。典型的值是 GET POST ,但也可以發送 HEAD 請求。
   ·url :要連接的 URL
   ·asynch :如果希望使用異步連接則爲 true ,否則爲 false 。該參數是可選的,默認爲 true
   ·username :如果需要身份驗證,則可以在此指定用戶名。該可選參數沒有默認值。
   ·password :如果需要身份驗證,則可以在此指定口令。該可選參數沒有默認值。
  通常使用其中的前三個參數。事實上,即使需要異步連接,也應該指定第三個參數爲 “true” 。這是默認值,但堅持明確指定請求是異步的還是同步的更容易理解。
  將這些結合起來,通常會得到 下列所示的一行代碼。

代碼4 getCustomerInfo() 方法的改進:

function getCustomerInfo() {
  var phone = document.getElementById("phone").value;
 var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
  request.open("GET", url, true);
}

   open() 是打開嗎?
  我們對 open() 方法到底做什麼沒有達成一致。但它實際上並不是 打開一個請求。如果監控 XHTML/Ajax 頁面及其連接腳本之間的網絡和數據傳遞,當調用 open() 方法時將看不到任何通信。

  一旦設置好了 URL ,其他就簡單了。多數請求使用 GET 就夠了,再加上 URL ,這就是使用 open() 方法需要的全部內容了。

3、發送請求
  一旦用 open() 配置好之後,就可以發送請求了。幸運的是,發送請求的方法的名稱要比 open() 適當,它就是 send()
   send()只有一個參數,就是要發送的內容。但是在考慮這個方法之前,回想一下前面已經通過URL 本身發送過數據了:

var url = "/cgi-local/lookupCustomer.jsp?phone=" + escape(phone);
  雖然可以使用 send() 發送數據,但也能通過 URL 本身發送數據。事實上, GET 請求(在典型的 Ajax 應用中大約佔 80% )中,用 URL 發送數據要容易得多。如果需要發送安全信息或 XML ,可能要考慮使用 send() 發送內容(關於如何使用POST方式安全的發送數據,請參考我的另外一篇文章--POST方式發送ajax請求詳解 )。如果不需要通過send()傳遞數據,則只要傳遞 null作爲該方法的參數即可。

代碼 5 getCustomerInfo() 方法的進一步改進:

function getCustomerInfo() {
  var phone = document.getElementById("phone").value;
  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
  request.open("GET", url, true);
  request.send(null);
}

4、指定回調方法
  現在我們所做的只有很少一點是新的、革命性的或異步的。必須承認, open() 方法中 “true” 這個小小的關鍵字建立了異步請求。但是 Ajax Web 2.0 最大的祕密是什麼呢?祕密就在於 XMLHttpRequest 的一個簡單屬性 onreadystatechange
  首先一定要理解這些代碼中的流程(如果需要請回顧 代碼 5 )。建立其請求然後發出請求。此外,因爲是異步請求,所以 JavaScript方法(例子中的getCustomerInfo() )不會等待服務器。因此代碼將繼續執行,就是說,將退出該方法而把控制返回給表單。用戶可以繼續輸入信息,應用程序不會等待服務器。
  這就提出了一個有趣的問題:服務器完成了請求之後會發生什麼?答案是什麼也不發生,至少對現在的代碼而言如此!顯然這樣不行,因此服務器在完成通過 XMLHttpRequest 發送給它的請求處理之後需要某種指示說明怎麼做。
  現在 onreadystatechange屬性該登場了。該屬性允許指定一個回調函數。回調允許服務器(猜得到嗎?)反向調用Web 頁面中的代碼。它也給了服務器一定程度的控制權,當服務器完成請求之後,會查看XMLHttpRequest對象,特別是 onreadystatechange 屬性。然後調用該屬性指定的任何方法。之所以稱爲回調是因爲服務器向網頁發起調用,無論網頁本身在做什麼。比方說,可能在用戶坐在椅子上手沒有碰鍵盤的時候調用該方法,但是也可能在用戶輸入、移動鼠標、滾動屏幕或者點擊按鈕時調用該方法。它並不關心用戶在做什麼。 這就是稱之爲異步的原因:用戶在一層上操作表單,而在另一層上服務器響應請求並觸發onreadystatechange屬性指定的回調方法。
   JavaScript 中引用函數
   JavaScript是一種弱類型的語言,可以用變量引用任何東西。因此如果聲明瞭一個函數updatePage()JavaScript 也將該函數名看作是一個變量。換句話說,可用變量名 updatePage 在代碼中引用函數。

 代碼 6.設置回調方法

function getCustomerInfo() {
  var phone = document.getElementById("phone").value;
  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
  request.open("GET", url, true);
  request.onreadystatechange = updatePage;
  request.send(null);
 }

  需要特別注意的是該屬性在代碼中設置的位置 —— 它是在調用 send() 之前 設置的。發送請求之前必須設置該屬性,這樣服務器在回答完成請求之後才能查看該屬性。

現在剩下的就只有編寫updatePage()方法了。

代碼 7. 檢查就緒狀態

function updatePage() {
  if (request.readyState == 4)
      if (request.status == 200)
       alert("Server is done!");
}

其中 request.readyState HTTP 的就緒狀態,在這裏我們大概需要了解這 5 種狀態,關於其詳細意義,我們在這就不在做深入研究了。

request.readyState == 0 :請求沒有發出(在調用open()之前)。
   request.readyState == 1 :請求已經建立但還沒有發出(調用 send() 之前)。
   request.readyState == 2 :請求已經發出正在處理之中(這裏通常可以從響應得到內容頭部)。
   request.readyState ==3 :請求已經處理,響應中通常有部分數據可用,但是服務器還沒有完成響應。
   request.readyState == 4 :響應已完成,可以訪問服務器響應並使用它。

而接下來的 request.status HTTP 狀態碼,爲 200 的時候爲正常, 400 多的時候爲客戶端的錯誤, 500 多的時候爲服務器端的服務,如果您對這方面的知識感興趣,不妨可以去借一些 HTTP 協議之類的書看看,這裏也不做深入研究了。

5、讀取響應文本

當我們成功做完上面的一切時,服務器最後給出了處理的響應,我們可以把響應的內容 以responseText 或者responseXML 形式組織返回給客戶端供其調用。responseXML 的話,要涉及到對 XML 的操作,因爲jdk 本身對XML 的操作比較弱,不過我們可以運用第三方的包org.jdom (網上有的下載),如果大家有興趣,可以自己去研究,這裏我們簡單的給出一個responseXML 的用法的例子

代碼 8. responseText 的簡單運用

function updatePage() {
   if (request.readyState == 4) {
   if (request.status == 200) {
    var response = request.responseText.split("|");
    document.getElementById("order").value = response[0];
    document.getElementById("address").innerHTML = response[1].replace(/\n/g, "");
   } else
    alert("status is " + request.status);
  }
   }

到現在,相信大家一定對 Ajax 有了一個系統的瞭解了吧,僅僅只是講了Ajax 的一些最基礎的東西,如果您對這個有興趣,還可以進行進一步的深入研究。

三、Ajax應用場景

然而 Ajax 不是萬能的,在適合的場合使用 Ajax ,才能充分發揮它的長處,改善系統性能和用戶體驗,絕不可以爲了技術而濫用。Ajax的特點在於異步交互,動態更新web頁面,因此它的適用範圍是交互較多,頻繁讀取數據的web應用。現在來看幾個Ajax的應用實例,讀者可以瞭解如何使用Ajax技術改進現有的 web應用系統。

場景 1. 數據驗證

在填寫表單內容時,需要保證數據的唯一性(例如新用戶註冊填寫的用戶名),因此必須對用戶輸入的內容進行數據驗證。數據驗證通常有兩種方式:一種是直接填寫,然後提交表單,這種方式需要將這個頁面提交到服務器端進行驗證,整個過程不僅時間長而且造成了服務器不必要的負擔;第二種方式是改進了的驗證過程,用戶可以通過點擊相應的驗證按鈕,打開新窗口查看驗證結果,但是這樣需要新開一個瀏覽器窗口或者對話框,還需要專門編寫驗證的頁面,比較耗費系統資源。而使用Ajax技術,可以由XMLHttpRequest對象發出驗證請求,根據返回的HTTP響應判斷驗證是否成功,整個過程不需要彈出新窗口,也不需要將整個頁面提交到服務器,快速而又不加重服務器負擔。

場景 2. 按需取數據

分類樹或者樹形結構在 web 應用系統中使用得非常廣泛,例如部門結構,文檔得分類結構常常使用樹形空間呈現。以前每次對分類樹得操作都會引起頁面重載,爲了避免這種情況出現,一般不採用每次調用後臺得方式,而是一次性將分類結果中得數據一次性讀取出來並寫入數組,然後根據用戶的操作,用JavaScript來控制節點的呈現,這樣雖然解決了操作響應速度,不重複載入頁面以及避免向服務器頻繁發送請求的問題,但是如果用戶不對分類進行操作或者只對分類樹中的一部分數據進行操作的話(這種情況很普遍的),那麼讀取的數據中就會有相當大的冗餘,浪費了用戶的資源。特別是在分類結構複雜,數據龐大的情況下,這種弊端就更加明顯了。

現在應用 Ajax 改進分類樹的實現機制。在初始化頁面時,只獲取第一級子分類的數據並且顯示;當用戶點開一級分類的第一節點時,頁面會通過Ajax向服務器請求當前分類所屬的二級子分類的所有數據;如果再請求已經呈現的二級分類的某一節點時,再次向服務器請求當前分類所屬的三級子分類的所有數據,以此類推。頁面會根據用戶的操作向服務器請求它所需要的數據,這樣就不會存在數據的冗餘,減少了數據下載總量。同時,更新頁面時不需要重載所有內容,只更新需要更新的那部分內容即可,相對於以前後臺處理並且重載的方式,大大縮短了用戶的等待時間。

場景 3. 自動更新頁面

web 應用中有很多數據的變化時十分迅速的,例如最新的熱點新聞,天氣預報以及聊天室內容等。在Ajax出現之前,用戶爲了即使瞭解相應的內容必須不斷刷新頁面,查看是否有新的內容變化,或者頁面本身實現定時刷新的功能(大多數聊天室頁面就是這樣做的)。有可能會發生這種情況;有一段時間網頁的內容沒有發生任何變化,但是用戶並不知道,仍然不斷的刷新頁面;或者用戶失去了耐心,放棄了刷新頁面,卻很有可能在此有新的消息出現,這樣就錯過了第一時間得到消息的機會。

應用 Ajax 可以改善這種這種情況,頁面加載以後,會通過Ajax引擎在後臺進行定時的輪詢,向服務器發送請求,查看是否有最新的消息。如果有則將新的數據(而不是所有數據)下載並且在頁面上進行動態的更新,通過一定的方式通知用戶(實現這樣的功能正是JavaScript的強項)。這樣即避免了用戶不斷手工刷新頁面的不便,也不會因爲重複刷新頁面造成資源浪費。

 

原文地址:http://www.cnblogs.com/jevonsea/archive/2011/05/23/2054330.html
發佈了39 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章