AJAX

瀏覽器與服務(wù)器之間,采用HTTP協(xié)議通信。用戶在瀏覽器地址欄鍵入一個(gè)網(wǎng)址,或者通過網(wǎng)頁表單向服務(wù)器提交內(nèi)容,這時(shí)瀏覽器就會(huì)向服務(wù)器發(fā)出HTTP請求。

1999年,微軟公司發(fā)布IE瀏覽器5.0版,第一次引入新功能:允許JavaScript腳本向服務(wù)器發(fā)起HTTP請求。這個(gè)功能當(dāng)時(shí)并沒有引起注意,直到2004年Gmail發(fā)布和2005年Google Map發(fā)布,才引起廣泛重視。2005年2月,AJAX這個(gè)詞第一次正式提出,指圍繞這個(gè)功能進(jìn)行開發(fā)的一整套做法。從此,AJAX成為腳本發(fā)起HTTP通信的代名詞,W3C也在2006年發(fā)布了它的國際標(biāo)準(zhǔn)。

具體來說,AJAX包括以下幾個(gè)步驟。

  1. 創(chuàng)建AJAX對象
  2. 發(fā)出HTTP請求
  3. 接收服務(wù)器傳回的數(shù)據(jù)
  4. 更新網(wǎng)頁數(shù)據(jù)

概括起來,就是一句話,AJAX通過原生的XMLHttpRequest對象發(fā)出HTTP請求,得到服務(wù)器返回的數(shù)據(jù)后,再進(jìn)行處理。

AJAX可以是同步請求,也可以是異步請求。但是,大多數(shù)情況下,特指異步請求。因?yàn)橥降腁jax請求,對瀏覽器有“堵塞效應(yīng)”。

注意,AJAX只能向同源網(wǎng)址(協(xié)議、域名、端口都相同)發(fā)出HTTP請求,如果發(fā)出跨源請求,就會(huì)報(bào)錯(cuò)。

1、AJAX 是什么?有什么作用?

  1. AJAX:是對Asynchronous JavaScript and XML的簡寫,是一種在無需重新加載整個(gè)網(wǎng)頁的情況下,能夠更新部分網(wǎng)頁的技術(shù)。這一技術(shù)能夠向服務(wù)器請求額外的數(shù)據(jù)而無需從新加載頁面。

  2. 作用:傳統(tǒng)的網(wǎng)頁(不使用 AJAX)如果需要更新內(nèi)容,必需重載整個(gè)網(wǎng)頁面。而通過使用ajax可以在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換, 可以使網(wǎng)頁實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁的情況下,對網(wǎng)頁的某部分進(jìn)行更新。

2、Ajax和XMLHttpRequest

Ajax核心的技術(shù)是XMLHttpRequest對象(簡稱XHR)。我們通常將Ajax等同于XMLHttpRequest,但細(xì)究起來它們兩個(gè)是屬于不同維度的2個(gè)概念。

Ajax:(摘自what is Ajax)AJAX stands for Asynchronous JavaScript and XML. AJAX is a new technique for creating better, faster, and more interactive web applications with the help of XML, HTML, CSS, and Java Script.
AJAX is based on the following open standards:

  • Browser-based presentation using HTML and Cascading Style Sheets (CSS).
  • Data is stored in XML format and fetched from the server.
  • Behind-the-scenes data fetches using XMLHttpRequest objects in the browser.
  • JavaScript to make everything happen.

從上面的解釋中可以知道:Ajax是一種技術(shù)方案,但并不是一種新技術(shù)。它依賴的是現(xiàn)有的CSS/HTML/Javascript,而其中最核心的依賴是瀏覽器提供的 XMLHttpRequest對象,是這個(gè)對象使得瀏覽器可以發(fā)出HTTP請求與接收HTTP響應(yīng)。

所以用一句話來總結(jié)兩者的關(guān)系,就是:我們使用XMLHttpRequest對象來發(fā)送一個(gè)Ajax請求。

3、XMLHttpRequest對象

1、什么是XMLHttpRequest?

  • XMLHttpRequest是原生JS的一個(gè)內(nèi)置對象,用來在瀏覽器與服務(wù)器之間傳送數(shù)據(jù),一旦拿到服務(wù)器返回的數(shù)據(jù),AJAX不會(huì)刷新整個(gè)網(wǎng)頁,而是只更新相關(guān)部分,從而不打斷用戶正在做的事情。XMLHttpRequestAJAX技術(shù)的核心,學(xué)習(xí)AJAX實(shí)質(zhì)上就是在學(xué)習(xí)XMLHttpRequest。

2、如何創(chuàng)建XMLHttpRequest對象:

  • 一般使用new關(guān)鍵字進(jìn)行創(chuàng)建,然后賦值給一個(gè)變量,如下:
var xhr = new XMLHttpRequest();

4、XMLHttpRequest對象的常用屬性

1、readyState

只讀屬性,表示XMLHttpRequest請求當(dāng)前所處的狀態(tài),共有五個(gè)數(shù)字值(0,1,2,3,4,5)。

  • 0:表示XMLHttpRequest實(shí)例已經(jīng)生成,但是open()方法還沒有被調(diào)用。
  • 1:表示已調(diào)用open方法,但還未調(diào)用send方法(請求還未被發(fā)送出去),仍然可以使用setRequestHeader(),設(shè)定HTTP請求的頭信息。
  • 2:表示send方法已調(diào)用,數(shù)據(jù)已發(fā)送,并且服務(wù)器接收到了請求。
  • 3:表示服務(wù)器正在傳輸數(shù)據(jù)。
  • 4:表示數(shù)據(jù)傳輸完成。

在通信過程中,每當(dāng)發(fā)生狀態(tài)變化的時(shí)候,readyState屬性的值就會(huì)發(fā)生改變。這個(gè)值每一次變化,都會(huì)觸發(fā)readyStateChange事件。

2、status

只讀屬性,表示本次請求所得到的HTTP狀態(tài)碼,返回一個(gè)整數(shù)。一般來說,如果通信成功的話,這個(gè)狀態(tài)碼是200。常用的有如下幾個(gè)狀態(tài)碼:

  • 200:OK(正常訪問);
  • 301:Moved Permanently(永久移動(dòng));
  • 302:Moved temporarily(暫時(shí)移動(dòng));
  • 304:Not Modified(未修改);
  • 307:Temporary Redirect(暫時(shí)重定向);
  • 401:Unauthorized (未授權(quán));
  • 403:Forbidden(禁止訪問);
  • 404:Not Found(未找到該網(wǎng)址);
  • 500:Internal Server Error (找到網(wǎng)址但服務(wù)器發(fā)生錯(cuò)誤);

基本上,只有200和304的狀態(tài)碼,表示服務(wù)器返回是正常狀態(tài)。|

3、 statusText

與status屬性類似,返回本次請求的狀態(tài),不同點(diǎn)在于,status只返回一個(gè)數(shù)字,而該屬性返回一個(gè)字符串 ,包含整個(gè)狀態(tài)信息,比如”200 OK“|

4、responseType

responseType屬性用來指定服務(wù)器返回?cái)?shù)據(jù)(xhr.response)的類型??赏ㄟ^對該屬性賦值來指定接收的數(shù)據(jù)類型,默認(rèn)為字符串,有如下幾種數(shù)據(jù)類型:

  • text:以字符串形式接收數(shù)據(jù);
  • json:以json對象形式接收數(shù)據(jù);
  • blob:blob對象;
  • ArrayBuffer:ArrayBuffer對象;

5、response、responseText、responseXML

三者都是服務(wù)器返回的數(shù)據(jù),如果數(shù)據(jù)不完整或者獲取失敗,它們的值就為null。

不同點(diǎn):

  • response返回的是數(shù)據(jù)的主體部分,可以為任何類型(數(shù)組,json,XML,字符串等);

  • responseText返回從服務(wù)器接收到的字符串。該屬性為只讀。如果本次請求沒有成功或者數(shù)據(jù)不完整,該屬性就會(huì)等于null。如果服務(wù)器返回的數(shù)據(jù)格式是JSON,就可以使用responseText屬性;

//返回JSON格式的字符串
var data = ajax.responseText;
//把JSON格式的字符串轉(zhuǎn)換為JavaScript對象
data = JSON.parse(data);
  • responseXML返回從服務(wù)器接收到的Document對象,該屬性為只讀。如果本次請求沒有成功,或者數(shù)據(jù)不完整,或者不能被解析為XML或HTML,該屬性等于null。該值返回的數(shù)據(jù)會(huì)被直接解析DOM;

5、XMLHttpRequest對象的常用方法

1、abort()

abort方法用來終止已經(jīng)發(fā)出的HTTP請求。

2、getAllResponseHeaders()

getAllResponseHeaders方法返回服務(wù)器發(fā)來的所有HTTP頭信息。格式為字符串,每個(gè)頭信息之間使用CRLF分隔,如果沒有受到服務(wù)器回應(yīng),該屬性返回null,該方法不需要接受參數(shù)。

3、getResponseHeader()

getResponseHeader方法返回HTTP頭信息指定字段的值,如果還沒有收到服務(wù)器回應(yīng)或者指定字段不存在,則該屬性為null。該方法需要接受一個(gè)參數(shù),用來返回指定字段的值。

4、open()

XMLHttpRequest對象的open方法用于指定發(fā)送HTTP請求的參數(shù),常用的有三個(gè)參數(shù):

  • 第一個(gè)參數(shù):請求的類型(常用get或者post);

  • 第二個(gè)參數(shù)是接口名和:這里要分兩種情況:

  • get請求時(shí):接口名+請求參數(shù)(鍵值對形式);post請求時(shí):只需要接口名(需要傳遞的參數(shù)寫在send方法里);

  • 第三個(gè)參數(shù):一個(gè)布爾值,指定是否異步(true為異步,false為同步,通常為true,默認(rèn)為true);

第四和第五個(gè)參數(shù):填寫用于認(rèn)證的用戶名和密碼;

5、send()

send方法用于實(shí)際發(fā)出HTTP請求。如果不帶參數(shù),就表示HTTP請求只包含頭信息,也就是只有一個(gè)URL,典型例子就是GET請求;如果帶有參數(shù),就表示除了頭信息,還帶有包含具體數(shù)據(jù)的信息體,典型例子就是POST請求。

如果是POST請求還要在open()之后、send()之前使setRequestHeader方法設(shè)置HTTP頭信息。

ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

6、setRequestHeader()

setRequestHeader方法用于設(shè)置HTTP頭信息。該方法必須在open()之后、send()之前調(diào)用。

6、XMLHttpRequest對象的事件以及對應(yīng)的事件監(jiān)聽接口

image.png

7、 前后端開發(fā)聯(lián)調(diào)需要注意哪些事情?后端接口完成前如何 mock 數(shù)據(jù)?

mock數(shù)據(jù)指的是在后端開發(fā)沒有完成時(shí),前端可以通過mock方法搭建本地服務(wù)器,模擬后臺(tái)數(shù)據(jù)來實(shí)現(xiàn)數(shù)據(jù)交互的效果

前后端開發(fā)聯(lián)調(diào)需要注意哪些事情:

  1. 約定數(shù)據(jù):有哪些需要傳輸?shù)臄?shù)據(jù),數(shù)據(jù)類型是什么。

  2. 約定接口:確定接口名稱以及請求和響應(yīng)的方法(get or post),請求的參數(shù)名稱,響應(yīng)的數(shù)據(jù)格式。

  3. 根據(jù)這些約定整理成接口文檔。

后端接口完成前如何 mock 數(shù)據(jù):

  1. 根據(jù)接口文檔,使用假數(shù)據(jù)來驗(yàn)證制作的網(wǎng)頁響應(yīng)和接口是否正常。

  2. 可以使用server-mock。

3,可以搭建php本地服務(wù)器用,php寫腳本提供臨時(shí)數(shù)據(jù)。

8、點(diǎn)擊按鈕,使用 ajax 獲取數(shù)據(jù),如何在數(shù)據(jù)到來之前防止重復(fù)點(diǎn)擊?

利用布爾值設(shè)置一個(gè)狀態(tài)鎖,在觸發(fā)ajax前和數(shù)據(jù)到來的時(shí)候布爾值設(shè)置為true,是不鎖定的;發(fā)送數(shù)據(jù)之后布爾值為false,是鎖定的。若重復(fù)點(diǎn)擊在數(shù)據(jù)沒有到來之前也就是布爾值為true時(shí),會(huì)把重復(fù)點(diǎn)擊忽略。

//利用布爾值作為狀態(tài)鎖
var lock = true; 
btn.addEventListener('click',function(){
   //用戶重復(fù)點(diǎn)擊,數(shù)據(jù)沒有到來之前直接return,忽略重復(fù)點(diǎn)擊
   if(!lock ){
     return;
   }
   ajax({
     ...
     //數(shù)據(jù)到來,布爾值設(shè)為true
     lock = true; 
   })
   xhr.open(...,...,...);
   xhr.send();
   //發(fā)送ajax請求,這時(shí)數(shù)據(jù)還沒有到來,布爾值設(shè)為false
   lock = false; 
});

9、封裝AJAX實(shí)現(xiàn)加載更多

這里使用server-mock來mock數(shù)據(jù)。server-mock是一款nodejs命令行工具,用于搭建web服務(wù)器,模擬網(wǎng)站后端,方便前端開發(fā)者M(jìn)ock數(shù)據(jù)。

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <style>
    ul,li{
      margin; 0;
      padding: 0
    }
    #ct li{
      list-style: none;
      border:1px solid #ccc;
      padding:10px;
      margin-top: 10px;
      cursor:pointer;
    }
    #load-more{
      display: block;
      margin:10px auto;
      text-align: center;
      cursor: pointer;
    }
    .btn{
      display: inline-block;;
      height: 40px;
      line-height: 40px;
      width: 80px;
      border: 1px solid #E27272;
      border-radius: 3px;
      text-align: center;
      text-decoration: none;
      color:#E27272;
    }
    .btn:hover{
      background: green;
      color:#fff;
    }
  </style>
</head>
<body>
  <ul id="ct">   
  </ul>
  <a id="load-more" class="btn" href="#">
    加載更多
  </a>
  <script>
    var btn = document.querySelector('#load-more');
    var ct = document.querySelector('#ct');
    var pageIndex = 0;
    //設(shè)置狀態(tài)鎖,防止數(shù)據(jù)到來之前用戶重復(fù)點(diǎn)擊
    var isDataArrive = true;

    btn.addEventListener('click',function (e) {
       e.preventDefault();
       
       if (!isDataArrive) {
       return;
       }

       loadData(function(news){
        renderPage(news);     
       })     
    })

    function loadData(callback){
      ajax({
        type: 'get',
        url: '/loadMore',
        data: {
          index: pageIndex,
          length: 5
        },
        onSuccess: callback,
        onError: function(){
          console.log('出錯(cuò)了')
        }
      })
    }

    function renderPage(results){
       var fragment = document.createDocumentFragment();
            for (var i = 0; i < results.length; i++) {
              var node = document.createElement('li');
              node.innerText = results[i];
              fragment.appendChild(node);
            }
            ct.appendChild(fragment)           
    }

    function ajax(options){
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function(){
        if (xhr.readyState === 4) {
          if (xhr.status === 200 || xhr.status === 304) {
            //與后端約定好,傳輸?shù)臄?shù)據(jù)類型為JSON字符串,JSON.parse()用來把JSON字符串解析為原生JavaScript值
            var results = JSON.parse(xhr.responseText);
            options.onSuccess(results);
            pageIndex = pageIndex + 5;
          }else{
            options.onError();
          }
          //數(shù)據(jù)到來,布爾值設(shè)為true
          isDataArrive = true
        }
      }

      var str = '';
      for(var key in options.data){
        str +=  key + '=' + options.data[key] + '&';   
      }
      str = str.substr(0, str.length-1);

      if(options.type.toLowerCase() === 'get'){
        xhr.open(options.type, options.url + '?' + str, true)
        xhr.send()
      }
      if(options.type.toLowerCase() === 'post'){
        xhr.open('post', options.url, true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send(str);
      }
      //發(fā)送ajax請求,這時(shí)數(shù)據(jù)還沒有到來,布爾值設(shè)為false
      isDataArrive = false;
    }
   
  </script>
</body>
</html>

router.js

app.get('/loadMore',function(req,res){

  var curIdx = req.query.index;
  var len= req.query.length;
  var data = [];

  for (var i = 0; i < len; i++) {
    data.push('新聞' + (parseInt(curIdx) + i))
  }

  res.send(data);
})


app.post('/loadMore',function(req,res){

  var curIdx = req.body.index;
  var len= req.body.length;
  var data = [];

  for (var i = 0; i < len; i++) {
    data.push('新聞' + (parseInt(curIdx) + i))
  }

  res.send(data);
})
image.png
image.png
image.png

每次點(diǎn)擊加載更多按鈕都會(huì)發(fā)送一條AJAX請求,數(shù)據(jù)沒回來之前,重復(fù)點(diǎn)擊會(huì)被忽略,數(shù)據(jù)到來后會(huì)渲染到頁面上出現(xiàn)5條新聞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容