AJAX完全解讀

本文講AJAX相關的知識全部講解了一遍.要想入門,選擇這篇文章完全夠用

本文的知識圖譜:
image.png

AJAX的用處:

​ 在沒有AJAX之前,每次從服務端獲取數據都要刷新頁面(也就是同步請求),這十分的麻煩。比如你要在一個網頁上的實時聊天框中聊天,要不停地刷新介面來獲取消息。這樣的行為也產生了大量無用,重複的數據擠占寬頻。

​ 因此AJAX應運而生,它可以在不刷新頁面的情況下讓頁面的一部分得到伺服器的數據,讓頁面產生變化。而做到這一切就使用了XMLHttpRequest組件,通過這個組件與伺服器保持非同步通訊和聯繫.

小概念

同步和非同步的概念

  • 同步:必須等待前面的任務完成,才能繼續後面的任務。
  • 非同步:不受當前任務的影響。

拿排隊舉例:

  • 同步:在銀行排隊時,只有等到你了,才能夠去處理業務。
  • 非同步:在排隊的時候,可以玩手機。

AJAX所使用的數據

image.png

XML

xml一般指可擴展標記語言標準通用標記語言的子集,簡稱XML。是一種用於標記電子文件使其具有結構性的標記語言

XML文檔的三個部分
image.png

XML聲明

<?xml version="1.0" encoding="utf-8"?>  

XML必須有version值,致命XML的版本號,同時定義文檔的字符集.

處理指令

處理指令,簡稱PI (processing instruction)。處理指令用來指揮解析引擎如何解析XML文檔內容。

語法

<?target instructions?>  

其中:

  • target – 標識指令指向哪個應用程式。
  • instruction – 字元,描述了應用程式要處理的資訊。

處理指令以特殊的 結尾。處理的內容在遇到字元串 ?> 時立即結束。

例如,在XML文檔中可以使用xml-stylesheet指令,通知XML解析引擎,應用css文件顯示xml文檔內容。**

<?xml-stylesheet type="text/css" href="1.css"?>  

XML結構數據

<?xml version="1.0"?> --XML聲明  <contact-info>      <name>Tanmay Patil</name>      <company>TutorialsPoint</company>      <phone>(011) 123-4567</phone>  </contact-info>  

XML結構數據中要有一個根<contact-info>和在其中的各種元素 <name>.所有的元素都必須被合併.

<name></name>

XML使用流程

image.png

XML DOM對象創建

要想處理XML就要創建一個XML DOM對象.

對於IE8以及早期的版本對於XML的支援通過基於ActiveX的MSXML組件實現.

var xmlDom=new ActiveXObject("Microsoft.XmlDom");  

現在的瀏覽器使用document對象中的Implementation屬性,使用該對象的createDocument()方法創建XML DOM對象.

createDocument("命名空間的URL字元串","包含文檔根元素名稱的字元串","創建文檔類型")

第三個現在總為null

示例:

 document.implementation.createDocument("","",null); //創建一個空的XML DOM文檔對象      document.implementation.createDocument("http://www.baidu.com","root",null); //第一個參數是命名空間,第二個是文檔的根節點名稱    

載入XML數據

載入數據有兩種方法load(),loadXML()

loadXML()

這種方法能將字元串轉換為XML DOM對象.

var o=document.implementation.createDocument("","",null); //必須先創建一個XML DOM對象之後才能載入  var s="<res><record>1</record><rename>蘋果</rename></res>"//一個XML字元串  o.loadXML(s);//載入XML字元串  

load()方法能夠載入XML文件

var o=document.implementation.createDocument("","",null); //必須先創建一個XML DOM對象  o.load("test.xml");  

同步模式下,XML文件被完全載入之後才能夠執行其他操作;而非同步載入時,用戶不用等待,可以執行其他操作

設置載入模式

load()方法默認載入模式為非同步載入,也可以使用async屬性來設置載入模式.

var o=document.implementation.createDocument("","",null);  var s="<res><record>1</record><rename>蘋果</rename></res>"//一個XML字元串  o.loadXML(s);//載入XML字元串  o.async=true;//非同步  o.async=false;//同步`  

XML DOM 對象使用readyState屬性跟蹤載入進程,readyState屬性的取值有5個.

0 尚未初始化    1 正在載入    2 完成載入    3 已經可用但是部分不可用    4 完全可用    

為此XML DOM對象有一個叫做onreadystatechange屬性,當每次readyState屬性發生變化之後,就會觸發readyState事件.

xmlhttp.onreadystatechange=function()//當readyState屬性發生變化,就觸發readyState    {    if (xmlhttp.readyState==4 && xmlhttp.status==200)//這個之後會講,      {      document.getElementById("myDiv").innerHTML=xmlhttp.responseText;      }    }  

顯示XML數據

XML嚴格執行DOM2標準,可以使用documenElement屬性獲取根元素,使用childNodes,firstNodes等都可以遍歷.(這個自己百度一下吧,就是用來訪問節點的屬性.功能很全,太多了)

function text(o) {          var s="";          for (var i=0;i<o.childNodes.length;i++){//遍歷子節點              if(o.childNodes[i].hasChildNodes()) {//如果當前節點在子節點                  a += text(o.childNodes[i]);//則遞歸讀取子節點包含的內容              }else{                  s+=o.childNodes[i].nodeValue;              }          }          return s;//返回節點內容      }  

還有一種方式就是可以使用XMLSerializer對象來實現

  function xml(o) {//傳入節點          var _o=new XMLSerializer();//創建XMLSerializer對象          return -o.serializeToString(o);//將節點的內容變成字元串      }  

好了這就是XML的全部內容

大體流程是這樣的:

image.png

下面來看JSON的內容

JSON的內容比較簡單

因為本身來講JSON就是一種遠比XML更加靈活的語言,

JSON](https://baike.baidu.com/item/JSON)(JavaScript Object Notation, JS 對象簡譜) 是一種輕量級的數據交換格式。它基於 ECMAScript (歐洲電腦協會制定的js規範)的一個子集,採用完全獨立於程式語言的文本格式來存儲和表示數據。簡潔和清晰的層次結構使得 JSON 成為理想的數據交換語言。 易於人閱讀和編寫,同時也易於機器解析和生成,並有效地提升網路傳輸效率。

下面是一個比較我就可以直觀的看到區別

JSON和XML的區別

來自烽火戲諸侯的程式碼

<?xml version="1.0" encoding="utf-8" ?>  <country>    <name>中國</name>    <province>      <name>黑龍江</name>      <citys>        <city>哈爾濱</city>        <city>大慶</city>      </citys>        </province>    <province>      <name>廣東</name>      <citys>        <city>廣州</city>        <city>深圳</city>        <city>珠海</city>      </citys>       </province>    <province>      <name>台灣</name>      <citys>         <city>台北</city>         <city>高雄</city>      </citys>     </province>    <province>      <name>新疆</name>      <citys>        <city>烏魯木齊</city>      </citys>    </province>  </country>  

JSON

var country =          {              name: "中國",              provinces: [              { name: "黑龍江", citys: { city: ["哈爾濱", "大慶"]} },              { name: "廣東", citys: { city: ["廣州", "深圳", "珠海"]} },              { name: "台灣", citys: { city: ["台北", "高雄"]} },              { name: "新疆", citys: { city: ["烏魯木齊"]} }              ]          }  

這麼一看就可以十分直觀的看出來,兩者的區別,在程式碼量上面XML是JSON的數倍之多.

結構也更加的複雜.

但是我么也要看到,XML有很強的可讀性,你幾乎不用非任何的力氣就了解他說表達的內容.

這兩點就是XML和JSON的差別

JSON的結構

JSON的結構由下面的三種類型的數據組成

值:字元串,數組,布爾值,對象,null,數值  對象:一組無序鍵值對  數組:一組有序的值列表,可以通過數組訪問其中的值.  

值:

1 -值  "helo ,world" -字元串  true,false  -布爾值  

對象

{      "name":"aaw4c", --兩者(值,鍵)必須都是字元串類型      "date":"2020",      "book":{  --json允許嵌套          "name":[{"lang":"cn","XPATH語言基礎"}] --數組       }  }  

數組

["value1","value2","value3"....]  

和JavaScript一樣這是數組直接量形式

[1,true,"false"]  

可以把不同類型的值放在一個數組中

解析JSON

ECMAScript5提供一個全局的JSON對象,用來序列化JSON

JSON.parse()能夠把一個json轉換成一個ECMAScript的值(對象或數組),

JSON.parse(text [,reviver)

JSON的格式一定要標準,key和value一定要用雙引號包括,否則會出現解析異常

var json='{"name":"張三","qq":"11111"}';  var contact=Json.parse(json);  document.write(contact.name+","+contact.qq);  

reviver是一個可選參數,他表示的是一個轉換函數,將傳入對象的每一個成員調用這個參數.

如果包含嵌套對象,則先於父對象轉換嵌套對象

  • 如果reviver函數返回一個有效值則成員值替換為轉換後的值
  • 如果reviver函數返回一個相同值則不變
  • 如果reviver函數返回一個null或undefined則刪除成員
  var a='{"a":"12","b":"13"}';        var contact=JSON.parse(a,int);          function int() { //reviver函數        if(typeof value=='string'){            return parseInt(value);        }else {            return value;        }      }    document.write(contact.b);//返回13  

使用AJAX

在這裡我們才終於講到了AJAX

但是還要降一點HTTP的知識,這樣才能更好的理解.

這是本文的HTTP知識圖表.
image.png

請求

HTTP的請求資訊由三部分組成:請求行,消息報頭,請求正文(可選)

<request-line>  <headers>  <blank line>  [<request-body>]  

請求行<request-line>以一個方法符號開頭,以空格分隔,後面跟著請求的URI和協議的版本

Method Request-URI HTTP-Version CRLF  

Method表示請求方法一般用大寫形式顯示如POST,GET.(HTTP定義了其他的,但是我們一般就用這倆)

Request-URI表示統一資源符

HTTP-Version表示請求的HTTP協議版本

CRLF表示回車換行

請求行之後是消息報頭部分消息報頭後是一個空行,然後才是請求正文

GET / HTTP/1.1 --Method Request-URI HTTP-Version (對號入座)  HOST:www.baidu.com --第一個消息報頭,HOST頭部指出的是請求的域名,結合上面的Request-URI,就可以的定位具體地址  User-Agent:Mozilla/5.0 --由瀏覽器進行定義  Connection: Keep-Alive-- 通常都設置為這個                              --這一行必須留空格  
POST / HTTP/ (CRLF) -post請求和get略有區別,首先從請求行開始處的get變成post  HOST:www.baidu.com  User-Agent:Mozilla/5.0 --由瀏覽器進行定義  Content-Type:application/x-www-form-urlencoded --需要增加的內容,說明請求主題內容是如何編碼  Content-Length:348 --必須增加的內容,請求的內容長度  Connection: Keep-Alive  

響應

HTTP響應也是由三個部分組成:狀態行,消息報頭,響應正文

<status-line>  <headers>  <blank line>  

狀態行<status-line>格式如下

HTTP-Version Status-Code Reason-Phrase CRLF  
HTTP-Version --表示伺服器的HTTP協議的版本  Status-Code --表示伺服器發回的響應狀態程式碼  Reason-Phrase --表示狀態程式碼的文本描述  

狀態程式碼:

1. 資訊提示 - 1xx  2. 成功 - 2xx  3. 重定向 - 3xx  4. 客戶端錯誤 - 4xx  5. 伺服器錯誤 - 5xx  

可以到以下鏈接中去具體了解.

狀態程式碼

響應示例:

HTTP/1.1 200 OK  Date: Thu, 16 Aug 2018 03:10:03 GMT  Server: Apache/2.4.18 (Win32) OpenSSL/1.0.2e mod_fcgid/2.3.9  X-Powered-By: PHP/5.5.30  Expires: Thu, 19 Nov 1981 08:52:00 GMT  Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0  Pragma: no-cache  Set-Cookie: XDEBUG_SESSION=netbeans-xdebug; expires=Thu, 16-Aug-2018 04:10:03 GMT; Max-Age=3600; path=/  Set-Cookie: _mcloudauth=xZ4y7BzG%2Bh3n4DAX1oy5wXUMZ0616h1WuywKO8Nf%2FcqI%3D59ec05a6d0b741340615114f8ea2a352; path=/; httponly  Keep-Alive: timeout=5, max=100  Connection: Keep-Alive  Transfer-Encoding: chunked  Content-Type: text/html; charset=UTF-8    35  {"code":0,"data":["mobile","13928892857"],"msg":"ok"}  0  

AJAX定義XMLHttpRequest對象

這其實才是AJAX的核心內容

XMLHttpRequest對象有各種屬性和方法

屬性

readyState --HTTP 請求的狀態  responseText --目前為止為伺服器接收到的響應體(不包括頭部),或者如果還沒有接收到數據的話,就是空字元串。  responseXML --對請求的響應,解析為 XML 並作為 Document 對象返回。  status --由伺服器返回的 HTTP 狀態程式碼,  statusText --這個屬性用名稱而不是數字指定了請求的 HTTP 的狀態程式碼。  

使用XMLHttpRequest對象實現非同步通訊一般需要下面幾個步驟

  1. 定義XMLHttpRequest實例對象

  2. 調用XMLHttpRequest對象的open方法打開伺服器端URL地址

  3. 註冊onreadystatechange事件處理函數,準備接受響應數據,並進行處理

  4. 調用XMLHttpRequest對象的send()方法發送請求

1.定義XMLHttpRequest實力對象

if (window.XMLHttpRequest)    {// code for all new browsers    xmlhttp=new XMLHttpRequest();//就這麼定義實例對象    }  else if (window.ActiveXObject)    {// code for IE5 and IE6    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");    }  //可以適配所有的瀏覽器  

2.調用XMLHttpRequest對象的open方法打開伺服器端URL地址

創建XMLHttpRequest對象之後,就可以使用該對象的open()方法建立一個HTTP請求.

open()方法如下

xmlhttp.open(bstrMethod,bstrUrl,varAsync,bstrUser,bstrPassword);  /*  bstrMethod:HTTP方法字元串,不分大小寫.例如GET,POST  bstrUrl:請求的URL地址字元串,可以為絕對地址或相對地址  varAsync:布爾值,可選參數,請求指定是否為非同步.  bstrUser:可選參數,要是需要驗證,從這裡輸入用戶名  bstrPassword:可選參數,要是需要驗證,從這裡輸入密碼  */    

一個小案例:

xmlhttp.open("GET",url,true);//只有前三個  

3.註冊onreadystatechange事件處理函數,準備接受響應數據,並進行處理

XMLHttpRequest對象的responseBody等.

4.調用XMLHttpRequest對象的send()方法發送請求

xmlhttp.send(box);  //box表示將要通過該請求發送的數據,如果不傳遞資訊則使用null  //這個方法中的同步方法取決於open()方法中的varAsync參數,如果為false,此方法會等待請求完成後返回,如果為true則立刻返回.  

這就是AJAX的主要步驟

發送GET請求

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Document</title>  </head>  <body>  <h1>Ajax 發送 get 請求</h1>  <input type="button" value="發送get_ajax請求" id='btnAjax'>    <script type="text/javascript">      // 綁定點擊事件      document.querySelector('#btnAjax').onclick = function () {          // 發送ajax 請求 需要 五步            // (1)創建非同步對象          var ajaxObj = new XMLHttpRequest();            // (2)設置請求的參數。包括:請求的方法、請求的url。          ajaxObj.open('get', '02-ajax.php');            // (3)發送請求          ajaxObj.send();            //(4)註冊事件。 onreadystatechange事件,狀態改變時就會調用。          //如果要在數據完整請求回來的時候才調用,我們需要手動寫一些判斷的邏輯。          ajaxObj.onreadystatechange = function () {              // 為了保證 數據 完整返回,我們一般會判斷 兩個值              if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {                  // 如果能夠進到這個判斷 說明 數據 完美的回來了,並且請求的頁面是存在的                  // 5.在註冊的事件中 獲取 返回的 內容 並修改頁面的顯示                  console.log('數據返回成功');                    // 數據是保存在 非同步對象的 屬性中                  console.log(ajaxObj.responseText);                    // 修改頁面的顯示                  document.querySelector('h1').innerHTML = ajaxObj.responseText;              }          }      }  </script>  </body>  </html>  

發送POST請求

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Document</title>  </head>  <body>  <h1>Ajax 發送 get 請求</h1>  <input type="button" value="發送put_ajax請求" id='btnAjax'>  <script type="text/javascript">        // 非同步對象      var xhr = new XMLHttpRequest();        // 設置屬性      xhr.open('post', '02.post.php');        // 如果想要使用post提交數據,必須添加此行      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");        // 將數據通過send方法傳遞      xhr.send('name=fox&age=18');        // 發送並接受返回值      xhr.onreadystatechange = function () {          // 這步為判斷伺服器是否正確響應          if (xhr.readyState == 4 && xhr.status == 200) {              alert(xhr.responseText);          }      };  </script>  </body>  </html>  

跟蹤狀態

XMLHttpRequest對象通過readyState屬性實時跟蹤非同步交互狀態

註冊 onreadystatechange 事件後,每當 readyState 屬性改變時,就會調用 onreadystatechange 函數。    readyState:(存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化)    0: 未初始化    1: 初始化,但是尚未調用send()    2: 發送數據,表示send()已經調用    3: 數據傳輸中,已經接收到部分數據    4: 請求已完成,且響應已就緒  

如果readyState屬性為4,則說明響應完畢,那麼就可以安全的讀取返回的數據.

在XMLHttpRequest對象中可以藉助status屬性獲取HTTP當前的狀態碼.如果readyState屬性為4且status為200則HTTP響應順利完成.

 if (ajaxObj.readyState == 4 && ajaxObj.status == 200)  

如下兩個則是兩種實例:

獲取XML數據

<!DOCTYPE html>  <html lang="en">  <head>  	<meta charset="UTF-8">  	<title>Document</title>  </head>  <body>  	<input type="button"  value="獲取XMl數據" id='getXML'>  </body>  </html>  <script type="text/javascript">  	document.querySelector('#getXML').onclick = function () {  		var ajax = new XMLHttpRequest();    		ajax.open('get','get_XMl.php');    		ajax.send();    		ajax.onreadystatechange = function () {  			if (ajax.readyState == 4 && ajax.status==200) {  				// 如果 返回的是 xml文件  				console.log(ajax.responseText);    				// 非同步 對象中 有另外一個屬性 用來專門獲取 xml  				// xml對象 在瀏覽器段 就是一個 document對象  				// 解析時 可以直接使用 querySelector 或者 getElementById等等 document對象 有的語法  				console.log(ajax.responseXML);  				console.log(ajax.responseXML.querySelector('kuzi').innerHTML);  				// 下面這個 頁面文檔對象 如果要獲取某個標籤  				console.log(window.document);    			}  		}  	}  </script>  

獲取JSON數據

<!DOCTYPE html>  <html lang="en">  <head>  	<meta charset="UTF-8">  	<title>Document</title>  </head>  <body>  	<h1>獲取 json 數據</h1>  	<input type="button"  value="獲取json" id='btnJson'>  </body>  </html>  <script type="text/javascript">  	// 獲取的是一個 如果要獲取多個  	// document.querySelectorAll(selector)  	document.querySelector("#btnJson").onclick = function () {  		var ajax = new XMLHttpRequest();    		ajax.open('get','myJson.php');    		ajax.send();    		ajax.onreadystatechange = function () {  			if (ajax.readyState==4&&ajax.status==200) {  				// json 字元串 是字元串 所以我們可以 通過  responseText獲取  				console.log(ajax.responseText);    				// 轉化為 js對象  				var jsObj = JSON.parse(ajax.responseText);    				console.log(jsObj);    				// 拼接ul s  				var str = '';    				str+='<ul>';  				str+='<li>'+jsObj.name+'</li>';  				str+='<li>'+jsObj.skill+'</li>';  				str+='<li>'+jsObj.friend+'</li>';  				str+='</ul>';    				// 設置到介面上    				document.body.innerHTML = str;  			}  		}  	}  </script>  

以上內容就是AJAX的內容了.

下面時AJAX的導圖,大家可以照著練習一下,看看自己是否記住了內容

image.png