Ajax初探(中)

上文,我們了解了網(wǎng)絡(luò)世界是如何交換信息的,用什么方式去交互信息(http),HTTP請(qǐng)求過(guò)程是如何實(shí)現(xiàn)的,什么是http請(qǐng)求,什么是http響應(yīng),說(shuō)了那么多,好像還沒(méi)說(shuō)到Ajax,不要急,下面我們就來(lái)實(shí)戰(zhàn)Ajax。

本文梗概:

Ajax實(shí)現(xiàn)的核心對(duì)象

  1. 牛刀小試——向服務(wù)器發(fā)送Ajax請(qǐng)求
  2. 更進(jìn)一步——獲取服務(wù)器返回的數(shù)據(jù)
  3. 開(kāi)始入門(mén)——了解異步與同步
  4. 再說(shuō)POST——發(fā)送POST請(qǐng)求
  5. Ajax總結(jié)

Ajax實(shí)現(xiàn)的核心對(duì)象

Ajax即“Asynchronous Javascript And XML”(異步JavaScript和XML),實(shí)際上跟XML沒(méi)多大關(guān)系,XML只是Ajax傳輸?shù)囊环N數(shù)據(jù)形式,也可以是JSON。實(shí)現(xiàn)它需要用到j(luò)avascript中的一個(gè)對(duì)象 XMLHttpRequest,簡(jiǎn)稱(chēng)XHR對(duì)象。

1. 牛刀小試——向服務(wù)器發(fā)送Ajax請(qǐng)求

PHP頁(yè)面的準(zhǔn)備
要學(xué)習(xí)Ajax,就需要和PHP打交道,在后臺(tái)接收我們發(fā)送的請(qǐng)求,下面寫(xiě)兩句PHP代碼,用來(lái)接收我們發(fā)送的Ajax請(qǐng)求

    <?php
      header("Content-type:text/html;charset=utf-8");
          if(!empty($_GET)){
            echo '你的數(shù)據(jù)我已經(jīng)接收到了,祝你生活愉快';
          }
    ?>

把這個(gè)頁(yè)面另存為server.php即可。


Javascript代碼的準(zhǔn)備

    window.onload = {
        document.onclick = function (){
          var xhr = new XMLHttpRequest();        //創(chuàng)建XHR對(duì)象
          xhr.open('get','server.php',false);        
          xhr.send(null);
  }
}

XHR對(duì)象有一個(gè)open方法,這個(gè)方法用于啟動(dòng)一個(gè)請(qǐng)求,以備發(fā)送。此方法有兩個(gè)必須的參數(shù):
a. 第一個(gè)是指定請(qǐng)求方式,get還是post[此參數(shù)大小寫(xiě)不敏感]
b. 第二個(gè)是發(fā)送請(qǐng)求的url,就是你要發(fā)送請(qǐng)求的那個(gè)頁(yè)面
c. 這里指定的第三個(gè)參數(shù)為發(fā)送異步請(qǐng)求還是同步請(qǐng)求,默認(rèn)為true,異步請(qǐng)求。

XHR對(duì)象的send方法則是將請(qǐng)求數(shù)據(jù)發(fā)送到服務(wù)器上,其參數(shù)有以下規(guī)定:
a. 如果使用GET方法,則參數(shù)為null,因?yàn)镚ET方法使用url傳參。
b. 如果使用POST方法,則參數(shù)為要發(fā)送的數(shù)據(jù)。


把html頁(yè)面和server.php服務(wù)器腳本丟到本地服務(wù)器中去測(cè)試 | php本地服務(wù)器如何搭建?

使用瀏覽器打開(kāi)你的HTML頁(yè)面,注意要在本地服務(wù)器打開(kāi)。然后打開(kāi)開(kāi)發(fā)者工具查看請(qǐng)求。刷新一下,就能看到面板上有一個(gè)HTML文件,點(diǎn)擊一下頁(yè)面,就可以看到一個(gè)請(qǐng)求發(fā)送到了服務(wù)器

Paste_Image.png
2. 更進(jìn)一步——獲取服務(wù)器返回的數(shù)據(jù)

請(qǐng)求已經(jīng)發(fā)送給服務(wù)器了,如無(wú)意外,服務(wù)器很快就可以給我們作出響應(yīng)并返回?cái)?shù)據(jù)了,那如何獲取服務(wù)器返回的數(shù)據(jù)呢?
使用XHR對(duì)象的responseText屬性
只有在send方法后面加上下面這段代碼就可以獲得響應(yīng)數(shù)據(jù)了。

alert(xhr.responseText);

但是實(shí)際上我們不一定都能夠成功地把請(qǐng)求發(fā)送到服務(wù)器的,所以必須要進(jìn)行判斷才能使用服務(wù)器的響應(yīng)數(shù)據(jù),怎么判斷?使用http狀態(tài)碼。
如果服務(wù)器成功接收請(qǐng)求,那么就會(huì)給客戶(hù)端返回一個(gè)200狀態(tài)碼,表示已經(jīng)成功接收請(qǐng)求,所請(qǐng)求的和響應(yīng)頭信息和數(shù)據(jù)隨即返回。
如果我們發(fā)送請(qǐng)求的地址錯(cuò)誤了,那么服務(wù)器就會(huì)返回一個(gè)404狀態(tài)碼,表示所請(qǐng)求資源不存在。所以在獲取響應(yīng)數(shù)據(jù)之前做一下判斷處理可以增強(qiáng)用戶(hù)體驗(yàn)

   if(xhr.status == 200){
     alert(xhr.responseText);
}else if(xhr.status == 400){
     alert('你所請(qǐng)求的資源不存在');
}

——但是返回的為什么是空的呢?因?yàn)槲覀兊恼?qǐng)求的數(shù)據(jù)都沒(méi)有發(fā)送!
剛剛說(shuō)了,GET方法使用url傳參,那么我們?cè)谠O(shè)置url的時(shí)候應(yīng)該設(shè)置我們的參數(shù)
所以我們應(yīng)該這樣設(shè)置open方法

open('get','server.php?123',false);
//向服務(wù)器發(fā)送123這個(gè)字符串

設(shè)置之后就能功能打印出服務(wù)器返回的數(shù)據(jù) "你的數(shù)據(jù)已經(jīng)接收,祝你生活愉快",這就是簡(jiǎn)單的客戶(hù)端與服務(wù)器端的交互。
這種交互是實(shí)時(shí)的,也就是說(shuō)你在服務(wù)器改動(dòng)數(shù)據(jù),客戶(hù)端無(wú)需刷新,依舊能得到服務(wù)器端的最新數(shù)據(jù)。(不信你自己改改那個(gè)字符串)。
但是在IE瀏覽器和火狐瀏覽器上,卻不能。原因是這些瀏覽器默認(rèn)使用了緩存數(shù)據(jù),當(dāng)我們?cè)俅伟l(fā)送請(qǐng)求的時(shí)候,瀏覽器不會(huì)重新從服務(wù)器上下載數(shù)據(jù),而是使用本地緩存的數(shù)據(jù),所以我們應(yīng)該在url上加上一個(gè)生成隨機(jī)數(shù)的js函數(shù),讓提交的請(qǐng)求url每次都不一樣,瀏覽器就不會(huì)使用緩存數(shù)據(jù)了。

open('get','server.php?rand='+Math.random(),false);
3. 開(kāi)始入門(mén)——了解異步與同步

Ajax真容易,就這樣就實(shí)現(xiàn)了?并不是!Ajax的精妙在于異步。那什么是同步,什么是異步呢?
解決這個(gè)問(wèn)題,先做一個(gè)小小的實(shí)驗(yàn)先。
在server.php文件中加上一個(gè)行代碼

    <?php
      header("Content-type:text/html;charset=utf-8");
       sleep(5);    //加上這句
          if(!empty($_GET)){
            echo '你的數(shù)據(jù)我已經(jīng)接收到了,祝你生活愉快';
          }
    ?>

然后在HTML頁(yè)面上觸發(fā)請(qǐng)求。
是不是要等5秒,提示才能彈出來(lái)?那是因?yàn)?秒后,服務(wù)器才給你返回響應(yīng)數(shù)據(jù),剛才那個(gè)代碼是讓服務(wù)器睡眠5秒,再執(zhí)行代碼。

這個(gè)睡眠5秒有什么用?
因?yàn)樵谔斐暇W(wǎng)的速度大家都明白,很多時(shí)候打開(kāi)一個(gè)網(wǎng)站如果網(wǎng)絡(luò)有延遲的話,可能要等待幾秒才能打開(kāi),所以這個(gè)睡眠5秒其實(shí)就是模擬網(wǎng)絡(luò)延遲。

先把sleep(5)注釋掉,點(diǎn)擊HTML頁(yè)面5次,連續(xù)彈出5個(gè)提示,如果不注釋那句代碼,連續(xù)點(diǎn)擊HTML頁(yè)面5次,會(huì)發(fā)生什么事?很顯然,需要等待25秒才能把提示全部彈出來(lái)。所以,同步[此例open方法設(shè)置同步] 請(qǐng)求需要等待服務(wù)器端響應(yīng)后才能發(fā)起第二次請(qǐng)求,這個(gè)等待服務(wù)器響應(yīng)的過(guò)程,客戶(hù)端是什么都不能干的,甚至?xí)霈F(xiàn)瀏覽器假死的狀況(卡住)


同步用戶(hù)體驗(yàn)糟糕透了,所以一般都不會(huì)使用同步請(qǐng)求,那異步請(qǐng)求又是怎么的?
其實(shí)很簡(jiǎn)單,只需要把open方法的false,改為true就可以了!

但是我們可以發(fā)現(xiàn)改了之后,點(diǎn)擊頁(yè)面一次,HTML頁(yè)面輸出的是第一次是空字符串,第二次才是響應(yīng)數(shù)據(jù),第三次還是響應(yīng)數(shù)據(jù),這是為什么?

因?yàn)閷?duì)于異步請(qǐng)求,瀏覽器將數(shù)據(jù)傳輸交給瀏覽器后臺(tái)處理,我們發(fā)送了請(qǐng)求,就馬上打印輸出數(shù)據(jù),當(dāng)然為空,要等到瀏覽器把數(shù)據(jù)完全接收完數(shù)據(jù)才能夠打印輸出。而同步之所以能夠打印輸出,是因?yàn)樗緛?lái)就必須等到客戶(hù)端完全接收數(shù)據(jù)才能夠?qū)?shù)據(jù)進(jìn)行處理,期間不能進(jìn)行任何操作,而異步在接收數(shù)據(jù)的同時(shí),是可以進(jìn)行其他操作的,比如說(shuō),我們?cè)诘却憫?yīng)的同時(shí),可以繼續(xù)發(fā)送請(qǐng)求。
簡(jiǎn)單的總結(jié)就是:

同步請(qǐng)求必須等到服務(wù)器器完全響應(yīng)了才能發(fā)起下一次請(qǐng)求
異步請(qǐng)求在客戶(hù)端等待服務(wù)器響應(yīng)的同時(shí)就可以發(fā)起下一次請(qǐng)求
5個(gè)同步請(qǐng)求完成需要25秒,5個(gè)異步請(qǐng)求完成,大概只需要6、7秒。

還有一個(gè)問(wèn)題沒(méi)有解決,為什么會(huì)彈出多次?
因?yàn)閷?duì)于異步請(qǐng)求,瀏覽器會(huì)有一個(gè)就緒狀態(tài),表明數(shù)據(jù)接收的狀態(tài)。一般我們使用就緒狀態(tài)事件監(jiān)聽(tīng)函數(shù)來(lái)捕獲這些狀態(tài)信息,再對(duì)數(shù)據(jù)進(jìn)行處理。

        window.onload = {
        document.onclick = function (){
          var xhr = new XMLHttpRequest();        //創(chuàng)建XHR對(duì)象
          xhr.onreadystatechange = function (){
              alert(xhr.readyState+'\n'+xhr.responseText);
        }
          xhr.open('get','server.php?rand='+Math.random()+'&num=123',true);        
          xhr.send(null);
  }

從上面的例子可以看出來(lái),當(dāng)readyState屬性的值為3和4的時(shí)候,才能接收到服務(wù)器的數(shù)據(jù)。
readystate是指客戶(hù)端在接收http響應(yīng)數(shù)據(jù)的時(shí)候的狀態(tài)

0表示XHR對(duì)象尚未建立
1表示尚未調(diào)用open方法
2表示已經(jīng)調(diào)用open方法,但是還未調(diào)用send方法發(fā)送
3.表示已經(jīng)調(diào)用send方法,但是返回的數(shù)據(jù)還不完整,尚且不能使用
4.表示已經(jīng)接收數(shù)據(jù)完畢,數(shù)據(jù)已經(jīng)可以使用。

所以正確使用異步請(qǐng)求的正確姿勢(shì),應(yīng)該是這樣的

  window.onload = {
        document.onclick = function (){
          var xhr = new XMLHttpRequest();        //創(chuàng)建XHR對(duì)象
          xhr.onreadystatechange = function (){
              if(xhr.readystatechange == 4  && xhr.status == 200){
                      alert(responseText);
                }
           }
          xhr.open('get','server.php?rand='+Math.random()+'&num=123',true);        
          xhr.send(null);
  }

4. 再說(shuō)POST——發(fā)送POST請(qǐng)求

上面一直都是使用GET方式發(fā)送請(qǐng)求,怎么樣發(fā)送POST方式請(qǐng)求呢?
先看代碼

  window.onload = {
        document.onclick = function (){
          var xhr = new XMLHttpRequest();        //創(chuàng)建XHR對(duì)象
          xhr.onreadystatechange = function (){
              if(xhr.readystatechange == 4  && xhr.status == 200){
                      alert(responseText);
                }
           }
          xhr.open('post','server.php?rand='+Math.random(),true); 
            //第一處改動(dòng),將get設(shè)置為post   
          xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');    
          // 第二處改動(dòng),設(shè)置了請(qǐng)求頭
          xhr.send('name=123');
          //第三處改動(dòng),send方法參數(shù)添加數(shù)據(jù)。
  }

對(duì)于第二處的解析:
服務(wù)器對(duì)于POST請(qǐng)求的解析方式和web表單提交是不同的所以,需要模擬表單進(jìn)行提交。[此處搞得不太明白。]

對(duì)于第三處的解析:
POST方法提交數(shù)據(jù)是模擬表單的形式發(fā)送的,所以需要使用鍵值對(duì)的方式提交服務(wù)器端才能接收。

POST請(qǐng)求的優(yōu)點(diǎn)與缺點(diǎn):
優(yōu)點(diǎn):

  1. 數(shù)據(jù)大小無(wú)限制,GET請(qǐng)求適合在服務(wù)器端查詢(xún)獲取數(shù)據(jù),而POST請(qǐng)求適合發(fā)送數(shù)據(jù)
  2. 數(shù)據(jù)被存放在實(shí)體中,不直接暴露在外,較GET方法安全。

缺點(diǎn):

  1. 性能上沒(méi)有GET方法快,因?yàn)榉?wù)器要對(duì)POST請(qǐng)求做特殊的處理。
5. Ajax總結(jié)

GET請(qǐng)求:

  1. 新建XHR對(duì)象
  2. 使用open方法啟動(dòng)請(qǐng)求,以備發(fā)送
  3. 使用就緒狀態(tài)監(jiān)聽(tīng)函數(shù),當(dāng)數(shù)據(jù)完全接收的時(shí)候,觸發(fā)函數(shù),獲取響應(yīng)數(shù)據(jù)
  4. 使用send方法發(fā)送請(qǐng)求,參數(shù)為null

[疑問(wèn):為什么就緒狀態(tài)監(jiān)聽(tīng)函數(shù)要寫(xiě)在sen方法前面呢?實(shí)際上寫(xiě)在后面也是可以的,但是寫(xiě)在前面表示先把這個(gè)方法載入內(nèi)存,觸發(fā)時(shí)調(diào)用,是個(gè)好習(xí)慣]

POST請(qǐng)求:

  1. 新建XHR對(duì)象
  2. 使用open方法啟動(dòng)請(qǐng)求,以備發(fā)送
  3. 設(shè)置http頭信息的Content-Type類(lèi)型,模擬表單發(fā)送
  4. 使用就緒狀態(tài)監(jiān)聽(tīng)函數(shù),當(dāng)數(shù)據(jù)完全接收的時(shí)候,觸發(fā)函數(shù),獲取響應(yīng)數(shù)據(jù)
  5. 使用send方法發(fā)送請(qǐng)求,參數(shù)為要發(fā)送的數(shù)據(jù)

寫(xiě)了那么多好像發(fā)現(xiàn)文字真的是太蒼白了,就算是我自己也會(huì)直接看教程而不是看這些無(wú)聊而神煩的文字,哈哈,算了,當(dāng)自己總結(jié)好了……下次盡量精簡(jiǎn)一些

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,746評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,991評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,706評(píng)論 6 413
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,036評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,203評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,451評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,677評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,857評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,266評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,606評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,407評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,643評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容