掌握 ajax,第 1 部分: ajax 簡介
http://www. 更新日期:2006-02-24 網(wǎng)頁教學網(wǎng) 瀏覽次數(shù):
brett mclaughlin , 作家,編輯, o‘reilly and associates 2006 年 1 月 04 日 五年前,如果不知道 xml,您就是一只無人重視的丑小鴨。十八個月前,ruby 成了關(guān)注的中心,不知道 ruby 的程序員只能坐冷板凳了。今天,如果想跟上最新的技術(shù)時尚,那您的目標就是 ajax。 但是,ajax 不僅僅是一種時尚,它是一種構(gòu)建網(wǎng)站的強大方法,而且不像學習一種全新的語言那樣困難。 但在詳細探討 ajax 是什么之前,先讓我們花幾分鐘了解 ajax 做什么。目前,編寫應用程序時有兩種基本的選擇: 桌面應用程序,web 應用程序。兩者是類似的,桌面應用程序通常以 cd 為介質(zhì)(有時候可從網(wǎng)站下載)并完全安裝到您的計算機上。桌面應用程序可能使用互聯(lián)網(wǎng)下載更新,但運行這些應用程序的代碼在桌面計算機上。web 應用程序運行在某處的 web 服務器上 —— 毫不奇怪,要通過 web 瀏覽器訪問這種應用程序。 不過,比這些應用程序的運行代碼放在何處更重要的是,應用程序如何運轉(zhuǎn)以及如何與其進行交互。桌面應用程序一般很快(就在您的計算機上運行,不用等待互聯(lián)網(wǎng)連接),具有漂亮的用戶界面(通常和操作系統(tǒng)有關(guān))和非凡的動態(tài)性。可以單擊、選擇、輸入、打開菜單和子菜單、到處巡游,基本上不需要等待。 另一方面,web 應用程序是最新的潮流,它們提供了在桌面上不能實現(xiàn)的服務(比如 amazon.com 和 ebay)。但是,伴隨著 web 的強大而出現(xiàn)的是等待,等待服務器響應,等待屏幕刷新,等待請求返回和生成新的頁面。 顯然這樣說過于簡略了,但基本的概念就是如此。您可能已經(jīng)猜到,ajax 嘗試建立桌面應用程序的功能和交互性,與不斷更新的 web 應用程序之間的橋梁??梢允褂孟褡烂鎽贸绦蛑谐R姷膭討B(tài)用戶界面和漂亮的控件,不過是在 web 應用程序中。 還等什么呢?我們來看看 ajax 如何將笨拙的 web 界面轉(zhuǎn)化成能迅速響應的 ajax 應用程序吧。 老技術(shù),新技巧 在談到 ajax 時,實際上涉及到多種技術(shù),要靈活地運用它必須深入了解這些不同的技術(shù)(本系列的頭幾篇文章將分別討論這些技術(shù))。好消息是您可能已經(jīng)非常熟悉其中的大部分技術(shù),更好的是這些技術(shù)都很容易學習,并不像完整的編程語言(如 java 或 ruby)那樣困難。 ajax 的定義 順便說一下,ajax 是 asynchronous javascript and xml(以及 dhtml 等)的縮寫。這個短語是 adaptive path 的 jesse james garrett 發(fā)明的,按照 jesse 的解釋,這不是個首字母縮寫詞。 下面是 ajax 應用程序所用到的基本技術(shù): html 用于建立 web 表單并確定應用程序其他部分使用的字段。 我們來進一步分析這些技術(shù)的職責。以后的文章中我將深入討論這些技術(shù),目前只要熟悉這些組件和技術(shù)就可以了。對這些代碼越熟悉,就越容易從對這些技術(shù)的零散了解轉(zhuǎn)變到真正把握這些技術(shù)(同時也真正打開了 web 應用程序開發(fā)的大門)。 xmlhttprequest 對象 要了解的一個對象可能對您來說也是最陌生的,即xmlhttprequest。這是一個 javascript 對象,創(chuàng)建該對象很簡單,如清單 1 所示。 清單 1. 創(chuàng)建新的 xmlhttprequest 對象 <script language="javascript" type="text/javascript"> 下一期文章中將進一步討論這個對象,現(xiàn)在要知道這是處理所有服務器通信的對象。繼續(xù)閱讀之前,先停下來想一想:通過xmlhttprequest對象與服務器進行對話的是 javascript 技術(shù)。這不是一般的應用程序流,這恰恰是 ajax 的強大功能的來源。 在一般的 web 應用程序中,用戶填寫表單字段并單擊 submit 按鈕。然后整個表單發(fā)送到服務器,服務器將它轉(zhuǎn)發(fā)給處理表單的腳本(通常是 php 或 java,也可能是 cgi 進程或者類似的東西),腳本執(zhí)行完成后再發(fā)送回全新的頁面。該頁面可能是帶有已經(jīng)填充某些數(shù)據(jù)的新表單的 html,也可能是確認頁面,或者是具有根據(jù)原來表單中輸入數(shù)據(jù)選擇的某些選項的頁面。當然,在服務器上的腳本或程序處理和返回新表單時用戶必須等待。屏幕變成一片空白,等到服務器返回數(shù)據(jù)后再重新繪制。這就是交互性差的原因,用戶得不到立即反饋,因此感覺不同于桌面應用程序。 ajax 基本上就是把 javascript 技術(shù)和xmlhttprequest對象放在 web 表單和服務器之間。當用戶填寫表單時,數(shù)據(jù)發(fā)送給一些 javascript 代碼而不是直接發(fā)送給服務器。相反,javascript 代碼捕獲表單數(shù)據(jù)并向服務器發(fā)送請求。同時用戶屏幕上的表單也不會閃爍、消失或延遲。換句話說,javascript 代碼在幕后發(fā)送請求,用戶甚至不知道請求的發(fā)出。更好的是,請求是異步發(fā)送的,就是說 javascript 代碼(和用戶)不用等待服務器的響應。因此用戶可以繼續(xù)輸入數(shù)據(jù)、滾動屏幕和使用應用程序。 然后,服務器將數(shù)據(jù)返回 javascript 代碼(仍然在 web 表單中),后者決定如何處理這些數(shù)據(jù)。它可以迅速更新表單數(shù)據(jù),讓人感覺應用程序是立即完成的,表單沒有提交或刷新而用戶得到了新數(shù)據(jù)。javascript 代碼甚至可以對收到的數(shù)據(jù)執(zhí)行某種計算,再發(fā)送另一個請求,完全不需要用戶干預!這就是xmlhttprequest的強大之處。它可以根據(jù)需要自行與服務器進行交互,用戶甚至可以完全不知道幕后發(fā)生的一切。結(jié)果就是類似于桌面應用程序的動態(tài)、快速響應、高交互性的體驗,但是背后又擁有互聯(lián)網(wǎng)的全部強大力量。 加入一些 javascript 得到xmlhttprequest的句柄后,其他的 javascript 代碼就非常簡單了。事實上,我們將使用 javascript 代碼完成非?;镜娜蝿眨?/p> 獲取表單數(shù)據(jù):javascript 代碼很容易從 html 表單中抽取數(shù)據(jù)并發(fā)送到服務器。 對于前兩點,需要非常熟悉getelementbyid()方法,如清單 2 所示。 清單 2. 用 javascript 代碼捕獲和設(shè)置字段值 / get the value of the "phone" field and stuff it in a variable called phone 這里沒有特別需要注意的地方,真是好極了!您應該認識到這里并沒有非常復雜的東西。只要掌握了xmlhttprequest,ajax 應用程序的其他部分就是如清單 2 所示的簡單 javascript 代碼了,混合有少量的 html。同時,還要用一點兒 dom,我們就來看看吧。 以 dom 結(jié)束 最后還有 dom,即文檔對象模型??赡軐τ行┳x者來說 dom 有點兒令人生畏,html 設(shè)計者很少使用它,即使 javascript 程序員也不大用到它,除非要完成某項高端編程任務。大量使用 dom 的是復雜的 java 和 c/c++ 程序,這可能就是 dom 被認為難以學習的原因。 幸運的是,在 javascript 技術(shù)中使用 dom 很容易,也非常直觀?,F(xiàn)在,按照常規(guī)也許應該說明如何使用 dom,或者至少要給出一些示例代碼,但這樣做也可能誤導您。即使不理會 dom,仍然能深入地探討 ajax,這也是我準備采用的方法。以后的文章將再次討論 dom,現(xiàn)在只要知道可能需要 dom 就可以了。當需要在 javascript 代碼和服務器之間傳遞 xml 和改變 html 表單的時候,我們再深入研究 dom。沒有它也能做一些有趣的工作,因此現(xiàn)在就把 dom 放到一邊吧。 獲取 request 對象 有了上面的基礎(chǔ)知識后,我們來看看一些具體的例子。xmlhttprequest是 ajax 應用程序的核心,而且對很多讀者來說可能還比較陌生,我們就從這里開始吧。從清單 1 可以看出,創(chuàng)建和使用這個對象非常簡單,不是嗎?等一等。 還記得幾年前的那些討厭的瀏覽器戰(zhàn)爭嗎?沒有一樣東西在不同的瀏覽器上得到同樣的結(jié)果。不管您是否相信,這些戰(zhàn)爭仍然在繼續(xù),雖然規(guī)模較小。但令人奇怪的是,xmlhttprequest成了這場戰(zhàn)爭的犧牲品之一。因此獲得xmlhttprequest對象可能需要采用不同的方法。下面我將詳細地進行解釋。 使用 microsoft 瀏覽器 microsoft 瀏覽器 internet explorer 使用 msxml 解析器處理 xml(可以通過參考資料進一步了解 msxml)。因此如果編寫的 ajax 應用程序要和 internet explorer 打交道,那么必須用一種特殊的方式創(chuàng)建對象。 但并不是這么簡單。根據(jù) internet explorer 中安裝的 javascript 技術(shù)版本不同,msxml 實際上有兩種不同的版本,因此必須對這兩種情況分別編寫代碼。請參閱清單 3,其中的代碼在 microsoft 瀏覽器上創(chuàng)建了一個xmlhttprequest。 清單 3. 在 microsoft 瀏覽器上創(chuàng)建 xmlhttprequest 對象 var xmlhttp = false; 您對這些代碼可能還不完全理解,但沒有關(guān)系。當本系列文章結(jié)束的時候,您將對 javascript 編程、錯誤處理、條件編譯等有更深的了解。現(xiàn)在只要牢牢記住其中的兩行代碼: xmlhttp = new activexobject("msxml2.xmlhttp"); 和 xmlhttp = new activexobject("microsoft.xmlhttp");。 這兩行代碼基本上就是嘗試使用一個版本的 msxml 創(chuàng)建對象,如果失敗則使用另一個版本創(chuàng)建該對象。不錯吧?如果都不成功,則將xmlhttp變量設(shè)為 false,告訴您的代碼出現(xiàn)了問題。如果出現(xiàn)這種情況,可能是因為安裝了非 microsoft 瀏覽器,需要使用不同的代碼。 處理 mozilla 和非 microsoft 瀏覽器 如果選擇的瀏覽器不是 internet explorer,或者為非 microsoft 瀏覽器編寫代碼,就需要使用不同的代碼。事實上就是清單 1 所示的一行簡單代碼: var xmlhttp = new xmlhttprequest object;。 這行簡單得多的代碼在 mozilla、firefox、safari、opera 以及基本上所有以任何形式或方式支持 ajax 的非 microsoft 瀏覽器中,創(chuàng)建了xmlhttprequest對象。 結(jié)合起來 關(guān)鍵是要支持所有瀏覽器。誰愿意編寫一個只能用于 internet explorer 或者非 microsoft 瀏覽器的應用程序呢?或者更糟,要編寫一個應用程序兩次?當然不!因此代碼要同時支持 internet explorer 和非 microsoft 瀏覽器。清單 4 顯示了這樣的代碼。 清單 4. 以支持多種瀏覽器的方式創(chuàng)建 xmlhttprequest 對象 /* create a new xmlhttprequest object to talk to the web server */ 現(xiàn)在先不管那些注釋掉的奇怪符號,如@cc_on,這是特殊的 javascript 編譯器命令,將在下一期針對xmlhttprequest的文章中詳細討論。這段代碼的核心分為三步: 1. 建立一個變量xmlhttp來引用即將創(chuàng)建的xmlhttprequest對象。 最后,xmlhttp應該引用一個有效的xmlhttprequest對象,無論運行什么樣的瀏覽器。 關(guān)于安全性的一點說明 安全性如何呢?現(xiàn)在瀏覽器允許用戶提高他們的安全等級,關(guān)閉 javascript 技術(shù),禁用瀏覽器中的任何選項。在這種情況下,代碼無論如何都不會工作。此時必須適當?shù)靥幚韱栴},這需要單獨的一篇文章來討論,要放到以后了(這個系列夠長了吧?不用擔心,讀完之前也許您就掌握了)。現(xiàn)在要編寫一段健壯但不夠完美的代碼,對于掌握 ajax 來說就很好了。以后我們還將討論更多的細節(jié)。 ajax 世界中的請求/響應 現(xiàn)在我們介紹了 ajax,對xmlhttprequest對象以及如何創(chuàng)建它也有了基本的了解。如果閱讀得很仔細,您可能已經(jīng)知道與服務器上的 web 應用程序打交道的是 javascript 技術(shù),而不是直接提交給那個應用程序的 html 表單。 還缺少什么呢?到底如何使用xmlhttprequest。因為這段代碼非常重要,您編寫的每個 ajax 應用程序都要以某種形式使用它,先看看 ajax 的基本請求/響應模型是什么樣吧。 發(fā)出請求 您已經(jīng)有了一個嶄新的xmlhttprequest對象,現(xiàn)在讓它干點活兒吧。首先需要一個 web 頁面能夠調(diào)用的 javascript 方法(比如當用戶輸入文本或者從菜單中選擇一項時)。接下來就是在所有 ajax 應用程序中基本都雷同的流程: 1. 從 web 表單中獲取需要的數(shù)據(jù)。 清單 5 中的示例 ajax 方法就是按照這個順序組織的: 清單 5. 發(fā)出 ajax 請求 function callserver() { 其中大部分代碼意義都很明確。開始的代碼使用基本 javascript 代碼獲取幾個表單字段的值。然后設(shè)置一個 php 腳本作為鏈接的目標。要注意腳本 url 的指定方式,city 和 state(來自表單)使用簡單的 get 參數(shù)附加在 url 之后。 然后打開一個連接,這是您第一次看到使用xmlhttprequest。其中指定了連接方法(get)和要連接的 url。最后一個參數(shù)如果設(shè)為true,那么將請求一個異步連接(這就是 ajax 的由來)。如果使用false,那么代碼發(fā)出請求后將等待服務器返回的響應。如果設(shè)為true,當服務器在后臺處理請求的時候用戶仍然可以使用表單(甚至調(diào)用其他 javascript 方法)。 xmlhttp(要記住,這是xmlhttprequest對象實例)的onreadystatechange屬性可以告訴服務器在運行完成后(可能要用五分鐘或者五個小時)做什么。因為代碼沒有等待服務器,必須讓服務器知道怎么做以便您能作出響應。在這個示例中,如果服務器處理完了請求,一個特殊的名為updatepage()的方法將被觸發(fā)。 最后,使用值null調(diào)用send()。因為已經(jīng)在請求 url 中添加了要發(fā)送給服務器的數(shù)據(jù)(city 和 state),所以請求中不需要發(fā)送任何數(shù)據(jù)。這樣就發(fā)出了請求,服務器按照您的要求工作。 如果沒有發(fā)現(xiàn)任何新鮮的東西,您應該體會到這是多么簡單明了!除了牢牢記住 ajax 的異步特性外,這些內(nèi)容都相當簡單。應該感激 ajax 使您能夠?qū)P木帉懫恋膽贸绦蚝徒缑?,而不用擔心復雜的 http 請求/響應代碼。 清單 5 中的代碼說明了 ajax 的易用性。數(shù)據(jù)是簡單的文本,可以作為請求 url 的一部分。用 get 而不是更復雜的 post 發(fā)送請求。沒有 xml 和要添加的內(nèi)容頭部,請求體中沒有要發(fā)送的數(shù)據(jù);換句話說,這就是 ajax 的烏托邦。 不用擔心,隨著本系列文章的展開,事情會變得越來越復雜。您將看到如何發(fā)送 post 請求、如何設(shè)置請求頭部和內(nèi)容類型、如何在消息中編碼 xml、如何增加請求的安全性,可以做的工作還有很多!暫時先不用管那些難點,掌握好基本的東西就行了,很快我們就會建立一整套的 ajax 工具庫。 處理響應 現(xiàn)在要面對服務器的響應了?,F(xiàn)在只要知道兩點: 什么也不要做,直到xmlhttp.readystate屬性的值等于 4。 服務器將把響應填充到xmlhttp.responsetext屬性中。 其中的第一點,即就緒狀態(tài),將在下一篇文章中詳細討論,您將進一步了解 http 請求的階段,可能比您設(shè)想的還多?,F(xiàn)在只要檢查一個特定的值(4)就可以了(下一期文章中還有更多的值要介紹)。第二點,使用xmlhttp.responsetext屬性獲得服務器的響應,這很簡單。清單 6 中的示例方法可供服務器根據(jù)清單 5 中發(fā)送的數(shù)據(jù)調(diào)用。 清單 6. 處理服務器響應 function updatepage() { 這些代碼同樣既不難也不復雜。它等待服務器調(diào)用,如果是就緒狀態(tài),則使用服務器返回的值(這里是用戶輸入的城市和州的 zip 編碼)設(shè)置另一個表單字段的值。于是包含 zip 編碼的zipcode字段突然出現(xiàn)了,而用戶沒有按任何按鈕!這就是前面所說的桌面應用程序的感覺??焖夙憫討B(tài)感受等等,這些都只因為有了小小的一段 ajax 代碼。 細心的讀者可能注意到zipcode是一個普通的文本字段。一旦服務器返回 zip 編碼,updatepage()方法就用城市/州的 zip 編碼設(shè)置那個字段的值,用戶就可以改寫該值。這樣做有兩個原因:保持例子簡單,說明有時候可能希望用戶能夠修改服務器返回的數(shù)據(jù)。要記住這兩點,它們對于好的用戶界面設(shè)計來說很重要。 連接 web 表單 還有什么呢?實際上沒有多少了。一個 javascript 方法捕捉用戶輸入表單的信息并將其發(fā)送到服務器,另一個 javascript 方法監(jiān)聽和處理響應,并在響應返回時設(shè)置字段的值。所有這些實際上都依賴于調(diào)用第一個 javascript 方法,它啟動了整個過程。最明顯的辦法是在 html 表單中增加一個按鈕,但這是 2001 年的辦法,您不這樣認為嗎?還是像清單 7 這樣利用 javascript 技術(shù)吧。 清單 7. 啟動一個 ajax 過程 <form> 如果感覺這像是一段相當普通的代碼,那就對了,正是如此!當用戶在 city 或 state 字段中輸入新的值時,callserver()方法就被觸發(fā),于是 ajax 開始運行了。有點兒明白怎么回事了吧?好,就是如此! |
|