|
使用 JavaScript 和 Ajax 發(fā)出異步請(qǐng)求(一) 多數(shù) Web 應(yīng)用程序都使用請(qǐng)求/響應(yīng)模型從服務(wù)器上獲得完整的 HTML 頁面。常常是點(diǎn)擊一個(gè)按鈕,等待服務(wù)器響應(yīng),再點(diǎn)擊另一個(gè)按鈕,然后再等待,這樣一個(gè)反復(fù)的過程。有了 Ajax 和 XMLHttpRequest 對(duì)象,就可以使用不必讓用戶等待服務(wù)器響應(yīng)的請(qǐng)求/響應(yīng)模型了。本文中,Brett McLaughlin 介紹了如何創(chuàng)建能夠適應(yīng)不同瀏覽器的 XMLHttpRequest 實(shí)例,建立和發(fā)送請(qǐng)求,并響應(yīng)服務(wù)器。 本文中,您將開始接觸最基本和基礎(chǔ)性的有關(guān) Ajax 的全部對(duì)象和編程方法:XMLHttpRequest 對(duì)象。該對(duì)象實(shí)際上僅僅是一個(gè)跨越所有 Ajax 應(yīng)用程序的公共線程,您可能已經(jīng)預(yù)料到,只有徹底理解該對(duì)象才能充分發(fā)揮編程的潛力。事實(shí)上,有時(shí)您會(huì)發(fā)現(xiàn),要正確地使用 XMLHttpRequest,顯然不能 使用 XMLHttpRequest。這到底是怎么回事呢? Web 2.0一瞥 在深入研究代碼之前首先看看最近的觀點(diǎn) —— 一定要十分清楚 Web 2.0 這個(gè)概念。聽到 Web 2.0 這個(gè)詞的時(shí)候,應(yīng)該首先問一問 “Web 1.0 是什么?” 雖然很少聽人提到 Web 1.0,實(shí)際上它指的就是具有完全不同的請(qǐng)求和響應(yīng)模型的傳統(tǒng) Web。比如,到 Amazon.com 網(wǎng)站上點(diǎn)擊一個(gè)按鈕或者輸入搜索項(xiàng)。就會(huì)對(duì)服務(wù)器發(fā)送一個(gè)請(qǐng)求,然后響應(yīng)再返回到瀏覽器。該請(qǐng)求不僅僅是圖書和書目列表,而是另一個(gè)完整的 HTML 頁面。因此當(dāng) Web 瀏覽器用新的 HTML 頁面重繪時(shí),可能會(huì)看到閃爍或抖動(dòng)。事實(shí)上,通過看到的每個(gè)新頁面可以清晰地看到請(qǐng)求和響應(yīng)。 Web 2.0(在很大程度上)消除了這種看得見的往復(fù)交互。比如訪問 Google Maps 或 Flickr 這樣的站點(diǎn)。比如在 Google Maps 上,您可以拖動(dòng)地圖,放大和縮小,只有很少的重繪操作。當(dāng)然這里仍然有請(qǐng)求和響應(yīng),只不過都藏到了幕后。作為用戶,體驗(yàn)更加舒適,感覺很像桌面應(yīng)用程序。這種新的感受和范型就是當(dāng)有人提到 Web 2.0 時(shí)您所體會(huì)到的。 需要關(guān)心的是如何使這些新的交互成為可能。顯然,仍然需要發(fā)出請(qǐng)求和接收響應(yīng),但正是針對(duì)每次請(qǐng)求/響應(yīng)交互的 HTML 重繪造成了緩慢、笨拙的 Web 交互的感受。因此很清楚,我們需要一種方法使發(fā)送的請(qǐng)求和接收的響應(yīng)只 包含需要的數(shù)據(jù)而不是整個(gè) HTML 頁面。惟一需要獲得整個(gè)新 HTML 頁面的時(shí)候就是希望用戶看到 新頁面的時(shí)候。 但多數(shù)交互都是在已有頁面上增加細(xì)節(jié)、修改主體文本或者覆蓋原有數(shù)據(jù)。這些情況下,Ajax 和 Web 2.0 方法允許在不 更新整個(gè) HTML 頁面的情況下發(fā)送和接收數(shù)據(jù)。對(duì)于那些經(jīng)常上網(wǎng)的人,這種能力可以讓您的應(yīng)用程序感覺更快、響應(yīng)更及時(shí),讓他們不時(shí)地光顧您的網(wǎng)站。 XMLHttpRequest 簡(jiǎn)介 要真正實(shí)現(xiàn)這種絢麗的奇跡,必須非常熟悉一個(gè) JavaScript 對(duì)象,即 XMLHttpRequest。這個(gè)小小的對(duì)象實(shí)際上已經(jīng)在幾種瀏覽器中存在一段時(shí)間了,它是本專欄今后幾個(gè)月中要介紹的 Web 2.0、Ajax 和大部分其他內(nèi)容的核心。為了讓您快速地大體了解它,下面給出將要用于該對(duì)象的很少的幾個(gè) 方法和屬性。 ?。畂pen():建立到服務(wù)器的新請(qǐng)求。 如果不了解這些(或者其中的任何 一個(gè)),您也不用擔(dān)心,后面幾篇文章中我們將介紹每個(gè)方法和屬性?,F(xiàn)在應(yīng)該 了解的是,明確用 XMLHttpRequest 做什么。要注意這些方法和屬性都與發(fā)送請(qǐng)求及處理響應(yīng)有關(guān)。事實(shí)上,如果看到 XMLHttpRequest 的所有方法和屬性,就會(huì)發(fā)現(xiàn)它們都 與非常簡(jiǎn)單的請(qǐng)求/響應(yīng)模型有關(guān)。顯然,我們不會(huì)遇到特別新的 GUI 對(duì)象或者創(chuàng)建用戶交互的某種超極神秘的方法,我們將使用非常簡(jiǎn)單的請(qǐng)求和非常簡(jiǎn)單的響應(yīng)。聽起來似乎沒有多少吸引力,但是用好該對(duì)象可以徹底改變您的應(yīng)用程序。 簡(jiǎn)單的 new 首先需要?jiǎng)?chuàng)建一個(gè)新變量并賦給它一個(gè) XMLHttpRequest 對(duì)象實(shí)例。這在 JavaScript 中很簡(jiǎn)單,只要對(duì)該對(duì)象名使用 new 關(guān)鍵字即可,如 清單 1 所示。 清單 1. 創(chuàng)建新的 XMLHttpRequest 對(duì)象 <script language="javascript" type="text/javascript"> 不難吧? 記住,JavaScript 不要求指定變量類型,因此不需要像清單2那樣做(在Java語言中可能需要這樣)。 清單 2. 創(chuàng)建 XMLHttpRequest 的 Java 偽代碼 XMLHttpRequest request = new XMLHttpRequest(); 因此在 JavaScript 中用 var 創(chuàng)建一個(gè)變量,給它一個(gè)名字(如 “request”),然后賦給它一個(gè)新的 XMLHttpRequest 實(shí)例。此后就可以在函數(shù)中使用該對(duì)象了。 錯(cuò)誤處理 在實(shí)際上各種事情都可能出錯(cuò),而上面的代碼沒有提供任何錯(cuò)誤處理。較好的辦法是創(chuàng)建該對(duì)象,并在出現(xiàn)問題時(shí)優(yōu)雅地退出。比如,任何較早的瀏覽器(不論您是否相信,仍然有人在使用老版本的 Netscape Navigator)都不支持 XMLHttpRequest,您需要讓這些用戶知道有些地方出了問題。清單 3 說明如何創(chuàng)建該對(duì)象,以便在出現(xiàn)問題的時(shí)候發(fā)出 JavaScript 警告。 清單 3. 創(chuàng)建具有錯(cuò)誤處理能力的 XMLHttpRequest <script language="javascript" type="text/javascript"> if (!request) 一定要理解這些步驟: 1. 創(chuàng)建一個(gè)新變量 request 并賦值 false。后面將使用 false 作為判定條件,它表示還沒有創(chuàng)建 XMLHttpRequest 對(duì)象。 2. 增加 try/catch 塊: 嘗試創(chuàng)建 XMLHttpRequest 對(duì)象。如果失敗(catch (failed))則保證 request 的值仍然為 false。 3. 檢查 request 是否仍為 false(如果一切正常就不會(huì)是 false)。 4. 如果出現(xiàn)問題(request 是 false)則使用 JavaScript 警告通知用戶出現(xiàn)了問題。 代碼非常簡(jiǎn)單,對(duì)大多數(shù) JavaScript 和 Web 開發(fā)人員來說,真正理解它要比讀寫代碼花更長(zhǎng)的時(shí)間?,F(xiàn)在已經(jīng)得到了一段帶有錯(cuò)誤檢查的 XMLHttpRequest 對(duì)象創(chuàng)建代碼,還可以告訴您哪兒出了問題。 應(yīng)付 Microsoft 看起來似乎一切良好,至少在用 Internet Explorer 試驗(yàn)這些代碼之前是這樣的。如果這樣試驗(yàn)的話,就會(huì)看到 Internet Explorer 報(bào)告錯(cuò)誤。 顯然有什么地方不對(duì)勁,而 Internet Explorer 很難說是一種過時(shí)的瀏覽器,因?yàn)槿澜缬?70% 在使用 Internet Explorer。換句話說,如果不支持 Microsoft 和 Internet Explorer 就不會(huì)受到 Web 世界的歡迎!因此我們需要采用不同的方法處理 Microsoft 瀏覽器。 經(jīng)驗(yàn)證發(fā)現(xiàn) Microsoft 支持 Ajax,但是其 XMLHttpRequest 版本有不同的稱呼。事實(shí)上,它將其稱為幾種 不同的東西。如果使用較新版本的 Internet Explorer,則需要使用對(duì)象 Msxml2.XMLHTTP,而較老版本的 Internet Explorer 則使用 Microsoft.XMLHTTP。我們需要支持這兩種對(duì)象類型(同時(shí)還要支持非 Microsoft 瀏覽器)。請(qǐng)看看 清單 4,它在前述代碼的基礎(chǔ)上增加了對(duì) Microsoft 的支持。 清單 4. 增加對(duì) Microsoft 瀏覽器的支持 <script language="javascript" type="text/javascript"> if (!request) 很容易被這些花括號(hào)迷住了眼睛,因此下面分別介紹每一步: 1. 創(chuàng)建一個(gè)新變量 request 并賦值 false。使用 false 作為判斷條件,它表示還沒有創(chuàng)建 XMLHttpRequest 對(duì)象。 2. 增加 try/catch 塊: 3. 檢查 request 是否仍然為 false(如果一切順利就不會(huì)是 false)。 4. 如果出現(xiàn)問題(request 是 false)則使用 JavaScript 警告通知用戶出現(xiàn)了問題。 這樣修改代碼之后再使用 Internet Explorer 試驗(yàn),就應(yīng)該看到已經(jīng)創(chuàng)建的表單(沒有錯(cuò)誤消息)。 靜態(tài)與動(dòng)態(tài) 再看一看清單 1、3 和 4,注意,所有這些代碼都直接嵌套在 script 標(biāo)記中。像這種不放到方法或函數(shù)體中的 JavaScript 代碼稱為靜態(tài) JavaScript。就是說代碼是在頁面顯示給用戶之前的某個(gè)時(shí)候運(yùn)行。(雖然根據(jù)規(guī)范不能完全精確地 知道這些代碼何時(shí)運(yùn)行對(duì)瀏覽器有什么影響,但是可以保證這些代碼在用戶能夠與頁面交互之前運(yùn)行。)這也是多數(shù) Ajax 程序員創(chuàng)建 XMLHttpRequest 對(duì)象的一般方式。 就是說,也可以像 清單 5 那樣將這些代碼放在一個(gè)方法中。 清單 5. 將 XMLHttpRequest 創(chuàng)建代碼移動(dòng)到方法中 <script language="javascript" type="text/javascript"> function createRequest() { if (!request) 如果按照這種方式編寫代碼,那么在處理 Ajax 之前需要調(diào)用該方法。因此還需要 清單 6 這樣的代碼。 清單 6. 使用 XMLHttpRequest 的創(chuàng)建方法 <script language="javascript" type="text/javascript"> var request; function createRequest() { if (!request) function getCustomerInfo() { 此代碼惟一的問題是推遲了錯(cuò)誤通知,這也是多數(shù) Ajax 程序員不采用這一方法的原因。假設(shè)一個(gè)復(fù)雜的表單有 10 或 15 個(gè)字段、選擇框等,當(dāng)用戶在第 14 個(gè)字段(按照表單順序從上到下)輸入文本時(shí)要激活某些 Ajax 代碼。這時(shí)候運(yùn)行 getCustomerInfo() 嘗試創(chuàng)建一個(gè) XMLHttpRequest 對(duì)象,但(對(duì)于本例來說)失敗了。然后向用戶顯示一條警告,明確地告訴他們不能使用該應(yīng)用程序。但用戶已經(jīng)花費(fèi)了很多時(shí)間在表單中輸入數(shù)據(jù)!這是非常令人討厭的,而討厭顯然不會(huì)吸引用戶再次訪問您的網(wǎng)站。 如果使用靜態(tài) JavaScript,用戶在點(diǎn)擊頁面的時(shí)候很快就會(huì)看到錯(cuò)誤信息。這樣也很煩人,是不是?可能令用戶錯(cuò)誤地認(rèn)為您的 Web 應(yīng)用程序不能在他的瀏覽器上運(yùn)行。不過,當(dāng)然要比他們花費(fèi)了 10 分鐘輸入信息之后再顯示同樣的錯(cuò)誤要好。因此,我建議編寫靜態(tài)的代碼,讓用戶盡可能早地發(fā)現(xiàn)問題。 用 XMLHttpRequest 發(fā)送請(qǐng)求 得到請(qǐng)求對(duì)象之后就可以進(jìn)入請(qǐng)求/響應(yīng)循環(huán)了。記住,XMLHttpRequest 惟一的目的是讓您發(fā)送請(qǐng)求和接收響應(yīng)。其他一切都是 JavaScript、CSS 或頁面中其他代碼的工作:改變用戶界面、切換圖像、解釋服務(wù)器返回的數(shù)據(jù)。準(zhǔn)備好 XMLHttpRequest 之后,就可以向服務(wù)器發(fā)送請(qǐng)求了。 歡迎使用沙箱 Ajax 采用一種沙箱安全模型。因此,Ajax 代碼(具體來說就是 XMLHttpRequest 對(duì)象)只能對(duì)所在的同一個(gè)域發(fā)送請(qǐng)求。以后的文章中將進(jìn)一步介紹安全和 Ajax,現(xiàn)在只要知道在本地機(jī)器上運(yùn)行的代碼只能對(duì)本地機(jī)器上的服務(wù)器端腳本發(fā)送請(qǐng)求。如果讓 Ajax 代碼在 www. 上運(yùn)行,則必須 www. 中運(yùn)行的腳本發(fā)送請(qǐng)求。 設(shè)置服務(wù)器 URL 首先要確定連接的服務(wù)器的 URL。這并不是 Ajax 的特殊要求,但仍然是建立連接所必需的,顯然現(xiàn)在您應(yīng)該知道如何構(gòu)造 URL 了。多數(shù)應(yīng)用程序中都會(huì)結(jié)合一些靜態(tài)數(shù)據(jù)和用戶處理的表單中的數(shù)據(jù)來構(gòu)造該 URL。比如,清單 7 中的 JavaScript 代碼獲取電話號(hào)碼字段的值并用其構(gòu)造 URL。 清單 7. 建立請(qǐng)求 URL <script language="javascript" type="text/javascript"> if (!request) function getCustomerInfo() { 這里沒有難懂的地方。首先,代碼創(chuàng)建了一個(gè)新變量 phone,并把 ID 為 “phone” 的表單字段的值賦給它。清單 8 展示了這個(gè)表單的 XHTML,其中可以看到 phone 字段及其 id 屬性。 清單 8. Break Neck Pizza 表單 <body> 還要注意,當(dāng)用戶輸入電話號(hào)碼或者改變電話號(hào)碼時(shí),將觸發(fā) 清單 8 所示的 getCustomerInfo() 方法。該方法取得電話號(hào)碼并構(gòu)造存儲(chǔ)在 url 變量中的 URL 字符串。記住,由于 Ajax 代碼是沙箱型的,因而只能連接到同一個(gè)域,實(shí)際上 URL 中不需要域名。該例中的腳本名為 /cgi-local/lookupCustomer.php。最后,電話號(hào)碼作為 GET 參數(shù)附加到該腳本中:"phone=" + escape(phone)。 如果以前沒用見過 escape() 方法,它用于轉(zhuǎn)義不能用明文正確發(fā)送的任何字符。比如,電話號(hào)碼中的空格將被轉(zhuǎn)換成字符 %20,從而能夠在 URL 中傳遞這些字符。 可以根據(jù)需要添加任意多個(gè)參數(shù)。比如,如果需要增加另一個(gè)參數(shù),只需要將其附加到 URL 中并用 “與”(&)字符分開 [第一個(gè)參數(shù)用問號(hào)(?)和腳本名分開]。 |
|
|