日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

掌握 Ajax,第 2 部分: 使用 JavaScript 和 Ajax 发出异步请求

發布時間:2023/12/18 javascript 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 掌握 Ajax,第 2 部分: 使用 JavaScript 和 Ajax 发出异步请求 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro2/

掌握 Ajax,第 2 部分: 使用 JavaScript 和 Ajax 發出異步請求

在 Web 請求中使用 XMLHttpRequest

多數 Web 應用程序都使用請求/響應模型從服務器上獲得完整的 HTML 頁面。常常是點擊一個按鈕,等待服務器響應,再點擊另一個按鈕,然后再等待,這樣一個反復的過程。有了 Ajax 和 XMLHttpRequest 對象,就可以使用不必讓用戶等待服務器響應的請求/響應模型了。本文中,Brett McLaughlin 介紹了如何創建能夠適應不同瀏覽器的 XMLHttpRequest 實例,建立和發送請求,并響應服務器。

Brett McLaughlin?(brett@newInstance.com), 作家,編輯, O'Reilly Media Inc.

2006 年 2 月 16 日

  • 內容

在 IBM Bluemix 云平臺上開發并部署您的下一個應用。

本系列的上一期文章(請參閱?參考資料?中的鏈接),我們介紹了 Ajax 應用程序,考察了推動 Ajax 應用程序的基本概念。其中的核心是很多您可能已經了解的技術:JavaScript、HTML 和 XHTML、一點動態 HTML 以及 DOM(文檔對象模型)。本文將放大其中的一點,把目光放到具體的 Ajax 細節上。

本文中,您將開始接觸最基本和基礎性的有關 Ajax 的全部對象和編程方法:XMLHttpRequest?對象。該對象實際上僅僅是一個跨越所有 Ajax 應用程序的公共線程,您可能已經預料到,只有徹底理解該對象才能充分發揮編程的潛力。事實上,有時您會發現,要正確地使用?XMLHttpRequest,顯然不能?使用XMLHttpRequest。這到底是怎么回事呢?

Web 2.0 一瞥

在深入研究代碼之前首先看看最近的觀點 —— 一定要十分清楚 Web 2.0 這個概念。聽到 Web 2.0 這個詞的時候,應該首先問一問 “Web 1.0 是什么?” 雖然很少聽人提到 Web 1.0,實際上它指的就是具有完全不同的請求和響應模型的傳統 Web。比如,到 Amazon.com 網站上點擊一個按鈕或者輸入搜索項。就會對服務器發送一個請求,然后響應再返回到瀏覽器。該請求不僅僅是圖書和書目列表,而是另一個完整的 HTML 頁面。因此當 Web 瀏覽器用新的 HTML 頁面重繪時,可能會看到閃爍或抖動。事實上,通過看到的每個新頁面可以清晰地看到請求和響應。

Web 2.0(在很大程度上)消除了這種看得見的往復交互。比如訪問 Google Maps 或 Flickr 這樣的站點(到這些支持 Web 2.0 和 Ajax 站點的鏈接請參閱?參考資料)。比如在 Google Maps 上,您可以拖動地圖,放大和縮小,只有很少的重繪操作。當然這里仍然有請求和響應,只不過都藏到了幕后。作為用戶,體驗更加舒適,感覺很像桌面應用程序。這種新的感受和范型就是當有人提到 Web 2.0 時您所體會到的。

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

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

XMLHttpRequest 簡介

要真正實現這種絢麗的奇跡,必須非常熟悉一個 JavaScript 對象,即?XMLHttpRequest。這個小小的對象實際上已經在幾種瀏覽器中存在一段時間了,它是本專欄今后幾個月中要介紹的 Web 2.0、Ajax 和大部分其他內容的核心。為了讓您快速地大體了解它,下面給出將要用于該對象的很少的幾個?方法和屬性。

  • open():建立到服務器的新請求。
  • send():向服務器發送請求。
  • abort():退出當前請求。
  • readyState:提供當前 HTML 的就緒狀態。
  • responseText:服務器返回的請求響應文本。

如果不了解這些(或者其中的任何?一個),您也不用擔心,后面幾篇文章中我們將介紹每個方法和屬性。現在應該?了解的是,明確用XMLHttpRequest?做什么。要注意這些方法和屬性都與發送請求及處理響應有關。事實上,如果看到?XMLHttpRequest?的所有方法和屬性,就會發現它們都?與非常簡單的請求/響應模型有關。顯然,我們不會遇到特別新的 GUI 對象或者創建用戶交互的某種超極神秘的方法,我們將使用非常簡單的請求和非常簡單的響應。聽起來似乎沒有多少吸引力,但是用好該對象可以徹底改變您的應用程序。

簡單的 new

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

清單 1. 創建新的 XMLHttpRequest 對象
<script language="javascript" type="text/javascript"> var request = new XMLHttpRequest(); </script>

不難吧?記住,JavaScript 不要求指定變量類型,因此不需要像?清單 2?那樣做(在 Java 語言中可能需要這樣)。

清單 2. 創建 XMLHttpRequest 的 Java 偽代碼
XMLHttpRequest request = new XMLHttpRequest();

因此在 JavaScript 中用?var?創建一個變量,給它一個名字(如 “request”),然后賦給它一個新的?XMLHttpRequest?實例。此后就可以在函數中使用該對象了。

錯誤處理

在實際上各種事情都可能出錯,而上面的代碼沒有提供任何錯誤處理。較好的辦法是創建該對象,并在出現問題時優雅地退出。比如,任何較早的瀏覽器(不論您是否相信,仍然有人在使用老版本的 Netscape Navigator)都不支持?XMLHttpRequest,您需要讓這些用戶知道有些地方出了問題。清單 3?說明如何創建該對象,以便在出現問題的時候發出 JavaScript 警告。

清單 3. 創建具有錯誤處理能力的 XMLHttpRequest
<script language="javascript" type="text/javascript"> var request = false; try {request = new XMLHttpRequest(); } catch (failed) {request = false; } if (!request)alert("Error initializing XMLHttpRequest!"); </script>

一定要理解這些步驟:

  • 創建一個新變量?request?并賦值 false。后面將使用 false 作為判定條件,它表示還沒有創建?XMLHttpRequest?對象。
  • 增加 try/catch 塊:
  • 嘗試創建?XMLHttpRequest?對象。
  • 如果失敗(catch (failed))則保證?request?的值仍然為 false。
  • 檢查?request?是否仍為 false(如果一切正常就不會是 false)。
  • 如果出現問題(request?是 false)則使用 JavaScript 警告通知用戶出現了問題。
  • 代碼非常簡單,對大多數 JavaScript 和 Web 開發人員來說,真正理解它要比讀寫代碼花更長的時間。現在已經得到了一段帶有錯誤檢查的XMLHttpRequest?對象創建代碼,還可以告訴您哪兒出了問題。

    應付 Microsoft

    看起來似乎一切良好,至少在用 Internet Explorer 試驗這些代碼之前是這樣的。如果這樣試驗的話,就會看到?圖 1?所示的糟糕情形。

    圖 1. Internet Explorer 報告錯誤

    Microsoft 參與了嗎?

    關于 Ajax 和 Microsoft 對該領域不斷增長的興趣和參與已經有很多文章進行了介紹。事實上,據說 Microsoft 最新版本的 Internet Explorer —— version 7.0,將在 2006 年下半年推出 —— 將開始直接支持?XMLHttpRequest,讓您使用?new?關鍵字代替所有的?Msxml2.XMLHTTP?創建代碼。但不要太激動,仍然需要支持舊的瀏覽器,因此跨瀏覽器代碼不會很快消失。

    顯然有什么地方不對勁,而 Internet Explorer 很難說是一種過時的瀏覽器,因為全世界有 70% 在使用 Internet Explorer。換句話說,如果不支持 Microsoft 和 Internet Explorer 就不會受到 Web 世界的歡迎!因此我們需要采用不同的方法處理 Microsoft 瀏覽器。

    經驗證發現 Microsoft 支持 Ajax,但是其?XMLHttpRequest?版本有不同的稱呼。事實上,它將其稱為幾種?不同的東西。如果使用較新版本的 Internet Explorer,則需要使用對象?Msxml2.XMLHTTP,而較老版本的 Internet Explorer 則使用?Microsoft.XMLHTTP。我們需要支持這兩種對象類型(同時還要支持非 Microsoft 瀏覽器)。請看看?清單 4,它在前述代碼的基礎上增加了對 Microsoft 的支持。

    清單 4. 增加對 Microsoft 瀏覽器的支持
    <script language="javascript" type="text/javascript"> 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;}} } if (!request)alert("Error initializing XMLHttpRequest!"); </script>

    很容易被這些花括號迷住了眼睛,因此下面分別介紹每一步:

  • 創建一個新變量?request?并賦值 false。使用 false 作為判斷條件,它表示還沒有創建?XMLHttpRequest?對象。
  • 增加 try/catch 塊:
  • 嘗試創建?XMLHttpRequest?對象。
  • 如果失敗(catch (trymicrosoft)):
  • 嘗試使用較新版本的 Microsoft 瀏覽器創建 Microsoft 兼容的對象(Msxml2.XMLHTTP)。
  • 如果失敗(catch (othermicrosoft))嘗試使用較老版本的 Microsoft 瀏覽器創建 Microsoft 兼容的對象(Microsoft.XMLHTTP)。
  • 如果失敗(catch (failed))則保證?request?的值仍然為 false。
  • 檢查?request?是否仍然為 false(如果一切順利就不會是 false)。
  • 如果出現問題(request?是 false)則使用 JavaScript 警告通知用戶出現了問題。
  • 這樣修改代碼之后再使用 Internet Explorer 試驗,就應該看到已經創建的表單(沒有錯誤消息)。我實驗的結果如?圖 2?所示。

    圖 2. Internet Explorer 正常工作

    靜態與動態

    再看一看清單?1、3?和?4,注意,所有這些代碼都直接嵌套在?script?標記中。像這種不放到方法或函數體中的 JavaScript 代碼稱為靜態 JavaScript。就是說代碼是在頁面顯示給用戶之前的某個時候運行。(雖然根據規范不能完全精確地?知道這些代碼何時運行對瀏覽器有什么影響,但是可以保證這些代碼在用戶能夠與頁面交互之前運行。)這也是多數 Ajax 程序員創建?XMLHttpRequest?對象的一般方式。

    就是說,也可以像?清單 5?那樣將這些代碼放在一個方法中。

    清單 5. 將 XMLHttpRequest 創建代碼移動到方法中
    <script language="javascript" type="text/javascript"> var request; function createRequest() {try {request = new XMLHttpRequest();} catch (trymicrosoft) {try {request = new ActiveXObject("Msxml2.XMLHTTP");} catch (othermicrosoft) {try {request = new ActiveXObject("Microsoft.XMLHTTP");} catch (failed) {request = false;}}}if (!request)alert("Error initializing XMLHttpRequest!"); } </script>

    如果按照這種方式編寫代碼,那么在處理 Ajax 之前需要調用該方法。因此還需要?清單 6?這樣的代碼。

    清單 6. 使用 XMLHttpRequest 的創建方法
    <script language="javascript" type="text/javascript"> var request; function createRequest() {try {request = new XMLHttpRequest();} catch (trymicrosoft) {try {request = new ActiveXObject("Msxml2.XMLHTTP");} catch (othermicrosoft) {try {request = new ActiveXObject("Microsoft.XMLHTTP");} catch (failed) {request = false;}}}if (!request)alert("Error initializing XMLHttpRequest!"); } function getCustomerInfo() {createRequest();// Do something with the request variable } </script>

    此代碼惟一的問題是推遲了錯誤通知,這也是多數 Ajax 程序員不采用這一方法的原因。假設一個復雜的表單有 10 或 15 個字段、選擇框等,當用戶在第 14 個字段(按照表單順序從上到下)輸入文本時要激活某些 Ajax 代碼。這時候運行?getCustomerInfo()?嘗試創建一個XMLHttpRequest?對象,但(對于本例來說)失敗了。然后向用戶顯示一條警告,明確地告訴他們不能使用該應用程序。但用戶已經花費了很多時間在表單中輸入數據!這是非常令人討厭的,而討厭顯然不會吸引用戶再次訪問您的網站。

    如果使用靜態 JavaScript,用戶在點擊頁面的時候很快就會看到錯誤信息。這樣也很煩人,是不是?可能令用戶錯誤地認為您的 Web 應用程序不能在他的瀏覽器上運行。不過,當然要比他們花費了 10 分鐘輸入信息之后再顯示同樣的錯誤要好。因此,我建議編寫靜態的代碼,讓用戶盡可能早地發現問題。

    用 XMLHttpRequest 發送請求

    得到請求對象之后就可以進入請求/響應循環了。記住,XMLHttpRequest?惟一的目的是讓您發送請求和接收響應。其他一切都是 JavaScript、CSS 或頁面中其他代碼的工作:改變用戶界面、切換圖像、解釋服務器返回的數據。準備好?XMLHttpRequest?之后,就可以向服務器發送請求了。

    歡迎使用沙箱

    Ajax 采用一種沙箱安全模型。因此,Ajax 代碼(具體來說就是?XMLHttpRequest?對象)只能對所在的同一個域發送請求。以后的文章中將進一步介紹安全和 Ajax,現在只要知道在本地機器上運行的代碼只能對本地機器上的服務器端腳本發送請求。如果讓 Ajax 代碼在 www.breakneckpizza.com 上運行,則必須 www.breakneck.com 中運行的腳本發送請求。

    設置服務器 URL

    首先要確定連接的服務器的 URL。這并不是 Ajax 的特殊要求,但仍然是建立連接所必需的,顯然現在您應該知道如何構造 URL 了。多數應用程序中都會結合一些靜態數據和用戶處理的表單中的數據來構造該 URL。比如,清單 7?中的 JavaScript 代碼獲取電話號碼字段的值并用其構造 URL。

    清單 7. 建立請求 URL
    <script language="javascript" type="text/javascript">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;} }}if (!request)alert("Error initializing XMLHttpRequest!");function getCustomerInfo() {var phone = document.getElementById("phone").value;var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);} </script>

    這里沒有難懂的地方。首先,代碼創建了一個新變量?phone,并把 ID 為 “phone” 的表單字段的值賦給它。清單 8?展示了這個表單的 XHTML,其中可以看到?phone?字段及其?id?屬性。

    清單 8. Break Neck Pizza 表單
    <body><p><img src="breakneck-logo_4c.gif" alt="Break Neck Pizza" /></p><form action="POST"><p>Enter your phone number:<input type="text" size="14" name="phone" id="phone" onChange="getCustomerInfo();" /></p><p>Your order will be delivered to:</p><div id="address"></div><p>Type 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>

    還要注意,當用戶輸入電話號碼或者改變電話號碼時,將觸發?清單 8?所示的?getCustomerInfo()?方法。該方法取得電話號碼并構造存儲在url?變量中的 URL 字符串。記住,由于 Ajax 代碼是沙箱型的,因而只能連接到同一個域,實際上 URL 中不需要域名。該例中的腳本名為/cgi-local/lookupCustomer.php。最后,電話號碼作為 GET 參數附加到該腳本中:"phone=" + escape(phone)。

    如果以前沒用見過?escape()?方法,它用于轉義不能用明文正確發送的任何字符。比如,電話號碼中的空格將被轉換成字符?%20,從而能夠在 URL 中傳遞這些字符。

    可以根據需要添加任意多個參數。比如,如果需要增加另一個參數,只需要將其附加到 URL 中并用 “與”(&)字符分開 [第一個參數用問號(?)和腳本名分開]。

    打開請求

    open() 是打開嗎?

    Internet 開發人員對?open()?方法到底做什么沒有達成一致。但它實際上并不是?打開一個請求。如果監控 XHTML/Ajax 頁面及其連接腳本之間的網絡和數據傳遞,當調用?open()?方法時將看不到任何通信。不清楚為何選用了這個名字,但顯然不是一個好的選擇。

    有了要連接的 URL 后就可以配置請求了。可以用?XMLHttpRequest?對象的?open()?方法來完成。該方法有五個參數:

    • request-type:發送請求的類型。典型的值是?GET?或?POST,但也可以發送?HEAD?請求。
    • url:要連接的 URL。
    • asynch:如果希望使用異步連接則為 true,否則為 false。該參數是可選的,默認為 true。
    • username:如果需要身份驗證,則可以在此指定用戶名。該可選參數沒有默認值。
    • password:如果需要身份驗證,則可以在此指定口令。該可選參數沒有默認值。

    通常使用其中的前三個參數。事實上,即使需要異步連接,也應該指定第三個參數為 “true”。這是默認值,但堅持明確指定請求是異步的還是同步的更容易理解。

    將這些結合起來,通常會得到?清單 9?所示的一行代碼。

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

    一旦設置好了 URL,其他就簡單了。多數請求使用?GET?就夠了(后面的文章中將看到需要使用?POST?的情況),再加上 URL,這就是使用open()?方法需要的全部內容了。

    挑戰異步性

    本系列的后面一篇文章中,我將用很多時間編寫和使用異步代碼,但是您應該明白為什么?open()?的最后一個參數這么重要。在一般的請求/響應模型中,比如 Web 1.0,客戶機(瀏覽器或者本地機器上運行的代碼)向服務器發出請求。該請求是同步的,換句話說,客戶機等待服務器的響應。當客戶機等待的時候,至少會用某種形式通知您在等待:

    • 沙漏(特別是 Windows 上)。
    • 旋轉的皮球(通常在 Mac 機器上)。
    • 應用程序基本上凍結了,然后過一段時間光標變化了。

    這正是 Web 應用程序讓人感到笨拙或緩慢的原因 —— 缺乏真正的交互性。按下按鈕時,應用程序實際上變得不能使用,直到剛剛觸發的請求得到響應。如果請求需要大量服務器處理,那么等待的時間可能很長(至少在這個多處理器、DSL 沒有等待的世界中是如此)。

    而異步請求不?等待服務器響應。發送請求后應用程序繼續運行。用戶仍然可以在 Web 表單中輸入數據,甚至離開表單。沒有旋轉的皮球或者沙漏,應用程序也沒有明顯的凍結。服務器悄悄地響應請求,完成后告訴原來的請求者工作已經結束(具體的辦法很快就會看到)。結果是,應用程序感覺不?那么遲鈍或者緩慢,而是響應迅速、交互性強,感覺快多了。這僅僅是 Web 2.0 的一部分,但它是很重要的一部分。所有老套的 GUI 組件和 Web 設計范型都不能克服緩慢、同步的請求/響應模型。

    發送請求

    一旦用?open()?配置好之后,就可以發送請求了。幸運的是,發送請求的方法的名稱要比?open()?適當,它就是?send()。

    send()?只有一個參數,就是要發送的內容。但是在考慮這個方法之前,回想一下前面已經通過 URL 本身發送過數據了:

    var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);

    雖然可以使用?send()?發送數據,但也能通過 URL 本身發送數據。事實上,GET?請求(在典型的 Ajax 應用中大約占 80%)中,用 URL 發送數據要容易得多。如果需要發送安全信息或 XML,可能要考慮使用?send()?發送內容(本系列的后續文章中將討論安全數據和 XML 消息)。如果不需要通過?send()?傳遞數據,則只要傳遞?null?作為該方法的參數即可。因此您會發現在本文中的例子中只需要這樣發送請求(參見?清單 10)。

    清單 10. 發送請求
    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);}

    指定回調方法

    現在我們所做的只有很少一點是新的、革命性的或異步的。必須承認,open()?方法中 “true” 這個小小的關鍵字建立了異步請求。但是除此之外,這些代碼與用 Java servlet 及 JSP、PHP 或 Perl 編程沒有什么兩樣。那么 Ajax 和 Web 2.0 最大的秘密是什么呢?秘密就在于XMLHttpRequest?的一個簡單屬性?onreadystatechange。

    首先一定要理解這些代碼中的流程(如果需要請回顧?清單 10)。建立其請求然后發出請求。此外,因為是異步請求,所以 JavaScript 方法(例子中的?getCustomerInfo())不會等待服務器。因此代碼將繼續執行,就是說,將退出該方法而把控制返回給表單。用戶可以繼續輸入信息,應用程序不會等待服務器。

    這就提出了一個有趣的問題:服務器完成了請求之后會發生什么?答案是什么也不發生,至少對現在的代碼而言如此!顯然這樣不行,因此服務器在完成通過?XMLHttpRequest?發送給它的請求處理之后需要某種指示說明怎么做。

    在 JavaScript 中引用函數

    JavaScript 是一種弱類型的語言,可以用變量引用任何東西。因此如果聲明了一個函數?updatePage(),JavaScript 也將該函數名看作是一個變量。換句話說,可用變量名?updatePage?在代碼中引用函數。

    現在?onreadystatechange?屬性該登場了。該屬性允許指定一個回調函數。回調允許服務器(猜得到嗎?)反向調用?Web 頁面中的代碼。它也給了服務器一定程度的控制權,當服務器完成請求之后,會查看?XMLHttpRequest?對象,特別是?onreadystatechange?屬性。然后調用該屬性指定的任何方法。之所以稱為回調是因為服務器向網頁發起調用,無論網頁本身在做什么。比方說,可能在用戶坐在椅子上手沒有碰鍵盤的時候調用該方法,但是也可能在用戶輸入、移動鼠標、滾動屏幕或者點擊按鈕時調用該方法。它并不關心用戶在做什么。

    這就是稱之為異步的原因:用戶在一層上操作表單,而在另一層上服務器響應請求并觸發?onreadystatechange?屬性指定的回調方法。因此需要像?清單 11?一樣在代碼中指定該方法。

    清單 11. 設置回調方法
    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()?方法了,這是本文最后一節要討論的重點。

    處理服務器響應

    發送請求,用戶高興地使用 Web 表單(同時服務器在處理請求),而現在服務器完成了請求處理。服務器查看?onreadystatechange?屬性確定要調用的方法。除此以外,可以將您的應用程序看作其他應用程序一樣,無論是否異步。換句話說,不一定要采取特殊的動作編寫響應服務器的方法,只需要改變表單,讓用戶訪問另一個 URL 或者做響應服務器需要的任何事情。這一節我們重點討論對服務器的響應和一種典型的動作 —— 即時改變用戶看到的表單中的一部分。

    回調和 Ajax

    現在我們已經看到如何告訴服務器完成后應該做什么:將?XMLHttpRequest?對象的?onreadystatechange?屬性設置為要運行的函數名。這樣,當服務器處理完請求后就會自動調用該函數。也不需要擔心該函數的任何參數。我們從一個簡單的方法開始,如?清單 12?所示。

    清單 12. 回調方法的代碼
    <script language="javascript" type="text/javascript">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;} }}if (!request)alert("Error initializing XMLHttpRequest!");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);}function updatePage() {alert("Server is done!");} </script>

    它僅僅發出一些簡單的警告,告訴您服務器什么時候完成了任務。在自己的網頁中試驗這些代碼,然后在瀏覽器中打開(如果希望查看該例中的 XHTML,請參閱?清單 8)。輸入電話號碼然后離開該字段,將看到一個彈出的警告窗口(如?圖 3?所示),但是點擊 OK 又出現了……

    圖 3. 彈出警告的 Ajax 代碼

    根據瀏覽器的不同,在表單停止彈出警告之前會看到兩次、三次甚至四次警告。這是怎么回事呢?原來我們還沒有考慮 HTTP 就緒狀態,這是請求/響應循環中的一個重要部分。

    HTTP 就緒狀態

    前面提到,服務器在完成請求之后會在?XMLHttpRequest?的?onreadystatechange?屬性中查找要調用的方法。這是真的,但還不完整。事實上,每當 HTTP 就緒狀態改變時它都會調用該方法。這意味著什么呢?首先必須理解 HTTP 就緒狀態。

    HTTP 就緒狀態表示請求的狀態或情形。它用于確定該請求是否已經開始、是否得到了響應或者請求/響應模型是否已經完成。它還可以幫助確定讀取服務器提供的響應文本或數據是否安全。在 Ajax 應用程序中需要了解五種就緒狀態:

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

    與大多數跨瀏覽器問題一樣,這些就緒狀態的使用也不盡一致。您也許期望任務就緒狀態從 0 到 1、2、3 再到 4,但實際上很少是這種情況。一些瀏覽器從不報告 0 或 1 而直接從 2 開始,然后是 3 和 4。其他瀏覽器則報告所有的狀態。還有一些則多次報告就緒狀態 1。在上一節中看到,服務器多次調用?updatePage(),每次調用都會彈出警告框 —— 可能和預期的不同!

    對于 Ajax 編程,需要直接處理的惟一狀態就是就緒狀態 4,它表示服務器響應已經完成,可以安全地使用響應數據了。基于此,回調方法中的第一行應該如?清單 13?所示。

    清單 13. 檢查就緒狀態
    function updatePage() {if (request.readyState == 4)alert("Server is done!");}

    修改后就可以保證服務器的處理已經完成。嘗試運行新版本的 Ajax 代碼,現在就會看到與預期的一樣,只顯示一次警告信息了。

    HTTP 狀態碼

    雖然?清單 13?中的代碼看起來似乎不錯,但是還有一個問題 —— 如果服務器響應請求并完成了處理但是報告了一個錯誤怎么辦?要知道,服務器端代碼應該明白它是由 Ajax、JSP、普通 HTML 表單或其他類型的代碼調用的,但只能使用傳統的 Web 專用方法報告信息。而在 Web 世界中,HTTP 代碼可以處理請求中可能發生的各種問題。

    比方說,您肯定遇到過輸入了錯誤的 URL 請求而得到 404 錯誤碼的情形,它表示該頁面不存在。這僅僅是 HTTP 請求能夠收到的眾多錯誤碼中的一種(完整的狀態碼列表請參閱?參考資料?中的鏈接)。表示所訪問數據受到保護或者禁止訪問的 403 和 401 也很常見。無論哪種情況,這些錯誤碼都是從完成的響應?得到的。換句話說,服務器履行了請求(即 HTTP 就緒狀態是 4)但是沒有返回客戶機預期的數據。

    因此除了就緒狀態外,還需要檢查 HTTP 狀態。我們期望的狀態碼是 200,它表示一切順利。如果就緒狀態是 4 而且狀態碼是 200,就可以處理服務器的數據了,而且這些數據應該就是要求的數據(而不是錯誤或者其他有問題的信息)。因此還要在回調方法中增加狀態檢查,如?清單 14?所示。

    清單 14. 檢查 HTTP 狀態碼
    function updatePage() {if (request.readyState == 4)if (request.status == 200)alert("Server is done!");}

    為了增加更健壯的錯誤處理并盡量避免過于復雜,可以增加一兩個狀態碼檢查,請看一看?清單 15?中修改后的?updatePage()?版本。

    清單 15. 增加一點錯誤檢查
    function updatePage() {if (request.readyState == 4)if (request.status == 200)alert("Server is done!");else if (request.status == 404)alert("Request URL does not exist");elsealert("Error: status code is " + request.status);}

    現在將?getCustomerInfo()?中的 URL 改為不存在的 URL 看看會發生什么。應該會看到警告信息說明要求的 URL 不存在 —— 好極了!很難處理所有的錯誤條件,但是這一小小的改變能夠涵蓋典型 Web 應用程序中 80% 的問題。

    讀取響應文本

    現在可以確保請求已經處理完成(通過就緒狀態),服務器給出了正常的響應(通過狀態碼),最后我們可以處理服務器返回的數據了。返回的數據保存在?XMLHttpRequest?對象的?responseText?屬性中。

    關于?responseText?中的文本內容,比如格式和長度,有意保持含糊。這樣服務器就可以將文本設置成任何內容。比方說,一種腳本可能返回逗號分隔的值,另一種則使用管道符(即?|?字符)分隔的值,還有一種則返回長文本字符串。何去何從由服務器決定。

    在本文使用的例子中,服務器返回客戶的上一個訂單和客戶地址,中間用管道符分開。然后使用訂單和地址設置表單中的元素值,清單 16?給出了更新顯示內容的代碼。

    清單 16. 處理服務器響應
    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, "
    ");
    } elsealert("status is " + request.status);}}

    首先,得到?responseText?并使用 JavaScript?split()?方法從管道符分開。得到的數組放到?response?中。數組中的第一個值 —— 上一個訂單 —— 用?response[0]?訪問,被設置為 ID 為 “order” 的字段的值。第二個值?response[1],即客戶地址,則需要更多一點處理。因為地址中的行用一般的行分隔符(“\n”字符)分隔,代碼中需要用 XHTML 風格的行分隔符?<br />?來代替。替換過程使用?replace()?函數和正則表達式完成。最后,修改后的文本作為 HTML 表單?div?中的內部 HTML。結果就是表單突然用客戶信息更新了,如圖 4 所示。

    圖 4. 收到客戶數據后的 Break Neck 表單

    結束本文之前,我還要介紹?XMLHttpRequest?的另一個重要屬性?responseXML。如果服務器選擇使用 XML 響應則該屬性包含(也許您已經猜到)XML 響應。處理 XML 響應和處理普通文本有很大不同,涉及到解析、文檔對象模型(DOM)和其他一些問題。后面的文章中將進一步介紹 XML。但是因為?responseXML?通常和?responseText?一起討論,這里有必要提一提。對于很多簡單的 Ajax 應用程序?responseText?就夠了,但是您很快就會看到通過 Ajax 應用程序也能很好地處理 XML。

    結束語

    您可能對?XMLHttpRequest?感到有點厭倦了,我很少看到一整篇文章討論一個對象,特別是這種簡單的對象。但是您將在使用 Ajax 編寫的每個頁面和應用程序中反復使用該對象。坦白地說,關于?XMLHttpRequest?還真有一些可說的內容。下一期文章中將介紹如何在請求中使用?POST?及GET,來設置請求中的內容頭部和從服務器響應讀取內容頭部,理解如何在請求/響應模型中編碼請求和處理 XML。

    再往后我們將介紹常見 Ajax 工具箱。這些工具箱實際上隱藏了本文所述的很多細節,使得 Ajax 編程更容易。您也許會想,既然有這么多工具箱為何還要對底層的細節編碼。答案是,如果不知道應用程序在做什么,就很難發現應用程序中的問題。

    因此不要忽略這些細節或者簡單地瀏覽一下,如果便捷華麗的工具箱出現了錯誤,您就不必撓頭或者發送郵件請求支持了。如果了解如何直接使用?XMLHttpRequest,就會發現很容易調試和解決最奇怪的問題。只有讓其解決您的問題,工具箱才是好東西。

    因此請熟悉?XMLHttpRequest?吧。事實上,如果您有使用工具箱的 Ajax 代碼,可以嘗試使用?XMLHttpRequest?對象及其屬性和方法重新改寫。這是一種不錯的練習,可以幫助您更好地理解其中的原理。

    下一期文章中將進一步討論該對象,探討它的一些更有趣的屬性(如?responseXML),以及如何使用?POST?請求和以不同的格式發送數據。請開始編寫代碼吧,一個月后我們再繼續討論。

    參考資料

    學習

    • 您可以參閱本文在 developerWorks 全球站點上的?英文原文。
    • 掌握 Ajax,第 1 部分: Ajax 簡介(developerWorks,2005 年 12 月)幫助您了解 Ajax,這是一種構建網站的高生產率方法。(本文中的參考資料列表都值得訪問!)
    • 面向 Java 開發人員的 Ajax: 構建動態的 Java 應用程序(developerWorks,2005 年 9 月)從 Java 的角度考察了 Ajax 服務器端。
    • 面向 Java 開發人員的 Ajax: Ajax 的 Java 對象序列化(developerWorks,2005 年 10 月)從 Java 的角度分析了如何通過網絡發送對象以及與 Ajax 交互。
    • 使用 AJAX 調用 SOAP Web 服務,第 1 部分: 構建 Web 服務客戶機(developerWorks,2005 年 10 月)是關于集成 Ajax 和現有基于 SOAP 的 web 服務的相當高級的文章。
    • Google GMail?是一個很好的例子,說明了基于 Ajax 的應用程序如何改變 Web 的工作方式。
    • Google Maps?是另一種基于 Google 的 Web 2.0 應用程序。
    • Flickr?是一個很好的例子,說明如何使用 Ajax 創建類似桌面的 Web 應用程序。
    • Ajax: A New Approach to Web Applications?發明了 Ajax 一詞,所有 Ajax 開發人員都應該讀一讀。
    • Why Ajax Matters Now?告訴您為什么 Ajax 很重要。
    • 如果使用的是 Microsoft 瀏覽器 Internet Explorer,請訪問?Microsoft Developer Network's XML Developer Center。
    • 請通過?在線文檔?進一步了解 MSXML,Microsoft XML 解析器。
    • 看一看響應中包含的所有?HTTP 狀態碼?列表。
    • developerWorks?Web Architecture 專區?專門發表各種基于 Web 的解決方案的文章。

    獲得產品和技術

    • Elisabeth Freeman、Eric Freeman 和 Brett McLaughlin 合著的?Head Rush Ajax(2005 年 2 月,O'Reilly Media, Inc.)以 Head First 風格將本文中所述的內容灌輸到您的頭腦中。
    • Java and XML, Second Edition(Brett McLaughlin,2001 年 8 月,O'Reilly Media, Inc.)包括作者關于 XHTML 和 XML 轉換的討論。
    • JavaScript: The Definitive Guide(David Flanagan,2001 年 11 月,O'Reilly Media, Inc.)詳細介紹了如何使用 JavaScript、動態網頁,第二版增加了關于 Ajax 的兩章。
    • Head First HTML with CSS & XHTML(Elizabeth 和Eric Freeman,2005 年 12 月,O'Reilly Media, Inc.)是學習 XHTML、CSS 以及如何將兩者結合起來的完整參考。

    討論

    • 參與論壇討論。
    • developerWorks blogs:加入 developerWorks 社區。

    轉載于:https://www.cnblogs.com/anruy/p/5038467.html

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的掌握 Ajax,第 2 部分: 使用 JavaScript 和 Ajax 发出异步请求的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。