深入理解ajax系列之一-XHR物件
概述
ajax是asynchronous javascript and XML的簡寫,中文翻譯是非同步的javascript和XML,這一技術能夠向伺服器請求額外的資料而無須解除安裝頁面,會帶來更好的使用者體驗。雖然名字中包含XML,但ajax通訊與資料格式無關。
ajax包括幾個步驟:
1:建立ajax請求,
2:發出http請求
3:收到伺服器傳回的訊息
4:更新網頁資料、
概括起來,就是一句話,ajax通過原生的XMLHttpRequest物件發出HTTP請求,得到伺服器返回的資料後,再進行處理。
建立
ajax技術的核心是XMLHttpRequest物件(簡稱XHR),這是由微軟首先引入的一個特性,其他瀏覽器提供商後來都提供了相同的實現。XHR為向伺服器傳送請求和解析伺服器響應提供了流暢的介面,能夠以非同步方式從伺服器取得更多資訊,意味著使用者單擊後,可以不必重新整理頁面也能取得新資料
IE5是第一款引入XHR物件的瀏覽器。在IE5中,XHR物件是通過MSXML庫中的一個ActiveX物件實現的,而IE7+及其他標準瀏覽器都支援原生的XHR物件
建立一個XHR物件,也叫例項化一個XHR物件,因為XMLHTTPRequest()是一個建構函式。下面是建立XHR物件的相容寫法
var xhr;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
[注意]如果要建立N個不同的請求,就要使用N個不同的XHR物件。當然可以重用已存在的XHR物件,但這會終止之前通過該物件掛起的任何請求。
發動請求
open();
在使用xrh的時候第一個呼叫的是open方法,如下,該方法接受3個引數,
xrh.open('GET','example.php',false);
open()方法的第一個引數用於指定傳送請求的方式,這個字串,不區分大小寫,但通常使用大寫字母。”GET”和”POST”是得到廣泛支援的.
‘GET’用於常規請求,它適用於URL完全指定的資源。當請求對伺服器沒有任何副作用是可快取的情況下,
‘POST’方法常用與HTML表單,他在請求主題中額外包含資料且這些資料常存在伺服器上的資料庫中。相同的URL的重複POST請求從伺服器的得到的相應可能不同
除了”GET”和”POST”之外,引數還可以是”HEAD”、”OPTIONS”、”PUT”。而由於安全風險的原因,”CONNECT”、”TRACE”、”TRACK”被禁止使用.
2. open()的第二個引數是URL,該URL對於執行程式碼的當前頁面,且只能想同一域中使用相同協議和埠的URL傳送請求。
3.open()的第三個引數是表示是否非同步傳送請求的值,如果不填寫。預設身高true,表示非同步傳送,
4.如果請求一個手密碼保護的URL用於認證的使用者和密碼作為第4和第5個引數傳遞給open()方法。
send()
send()方法接受一個引數,即作為請求主題傳送的資料。呼叫send()方法後,請求被分配到伺服器。
如果是GET方法,send()方法無引數,或引數為null;如果是POST方法,send()方法的引數是要傳送的的資料。
xhr.open("GET","xxx.php",true)
xhr.send(null);
接受響應
一個完整的http響應是有狀態嗎,響應頭集合,和響應主題組成。在收到響應的訊息後,這些都是可以通過xhr物件的屬性個方法所使用,主要有一下4個屬性
responseText;作為相應主題返回的文字,(文字形式)
responseXML;如果響應的內容是‘text/xml’或者是哦application/xml;屬性中將會儲存,響應資料的xml形式。DOM文件形式。
status: http的狀態碼(數字形式)
statusText;http狀態說明,(文字形式)
收到響應後,第一步是檢查status,以確定響應已經成功的返回,一般來說。http狀態碼200作為成功的標誌。此時,responseText屬性的內容也已經準備就緒,而且在內容正確的情況下,responseText的內容也可以訪問了,此外狀態碼304表示資源並沒有被修改,可以直接使用瀏覽器中的快取。
無論響應內容是什麼型別。都會被儲存在responseText中,而對於非XML資料而言,responseText的值則為null;
除了"GET"和"POST"之外,引數還可以是"HEAD"、"OPTIONS"、"PUT"。而由於安全風險的原因,"CONNECT"、"TRACE"、"TRACK"被禁止使用
同步
如果接受的是同步響應,在在open()方法的第三個引數設定為false,那麼send()方法將阻塞,直到請求完成,一旦send()返回,僅需檢查XHR物件的responseText屬性和status即可。
同步請求是吸引人的,但應該避免使用它們。客戶端javascript是單執行緒的,當send()方法阻塞時,它通常會導致整個瀏覽器UI凍結。如果連線的伺服器響應慢,那麼使用者的瀏覽器將凍結
<button id="btn">點選</button>
<div id=result></div>
<script>
btn.onclick=function(){
var xhr;
if(window.XMLHttpRequst){
var xhr = window.XMLHttpRequst;
}else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
//傳送請求
xhr.open("GET","xx.xml",false);
xhr.send();
//同步接受響應
if(xhr.readyState==4){
if(xhr.status == 200){
result.innerHTML += xhr.responseText;
}
}
}
</script>
//message.xml
<p>hello world</p>
非同步
如果接受的非同步響應,這就需要檢測XHR的readyState的屬性,該屬性表示,請求/響應過程中當前的活動階段,這個屬性可以去一下的值,
0(UNSENT):未初始化。尚未呼叫open()方法
1(OPENED):啟動。已經呼叫open()方法,但尚未呼叫send()方法
2(HEADERS_RECEIVED):傳送。己經呼叫send()方法,且接收到頭資訊
3(LOADING):接收。已經接收到部分響應主體資訊
4(DONE):完成。已經接收到全部響應資料,而且已經可以在客戶端使用了
理論上,只要readyState屬性的值由一個值變為另一個值,就會出發一次readyStatechange事件,可以利用這個事件來檢測每次狀態變化的readyState的值,我們對readyState值為4的階段感興趣,因為這時所有資料都已就緒,
<button id="btn">獲取資訊</button>
<div id="result"></div>
<script>
btn.onclick = function(){
//建立xhr物件
var xhr;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
//非同步接受響應
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
//實際操作
result.innerHTML += xhr.responseText;
}
}
}
//傳送請求
xhr.open('get','message.xml',true);
xhr.send();
}
</script>
超時
xhr.open("GET","xxx.php",true);
xhr.ontimeout=function(){
console.log("請求超市")
}
xhr.timeout = 1000;
xhr.send();
優化
使用AJAX接收資料時,由於網路和資料大小的原因,並不是立刻就可以在頁面中顯示出來。所以,更好的做法是,在接受資料的過程中,顯示一個類似loading的小圖片,並且禁用按鈕;當資料完全接收後,再隱藏該圖片,並啟用按鈕。
<button id="btn">獲取資訊</button>
<img id="img" height="16" style="display:none" src="data:image/gif;base64,R0lGODlhIAAgALMAAP///7Ozs/v7+9bW1uHh4fLy8rq6uoGBgTQ0NAEBARsbG8TExJeXl/39/VRUVAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBQAAACwAAAAAIAAgAAAE5xDISSlLrOrNp0pKNRCdFhxVolJLEJQUoSgOpSYT4RowNSsvyW1icA16k8MMMRkCBjskBTFDAZyuAEkqCfxIQ2hgQRFvAQEEIjNxVDW6XNE4YagRjuBCwe60smQUDnd4Rz1ZAQZnFAGDd0hihh12CEE9kjAEVlycXIg7BAsMB6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YEvpJivxNaGmLHT0VnOgGYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ/V/nmOM82XiHQjYKhKP1oZmADdEAAAh+QQFBQAAACwAAAAAGAAXAAAEchDISasKNeuJFKoHs4mUYlJIkmjIV54Soypsa0wmLSnqoTEtBw52mG0AjhYpBxioEqRNy8V0qFzNw+GGwlJki4lBqx1IBgjMkRIghwjrzcDti2/Gh7D9qN774wQGAYOEfwCChIV/gYmDho+QkZKTR3p7EQAh+QQFBQAAACwBAAAAHQAOAAAEchDISWdANesNHHJZwE2DUSEo5SjKKB2HOKGYFLD1CB/DnEoIlkti2PlyuKGEATMBaAACSyGbEDYD4zN1YIEmh0SCQQgYehNmTNNaKsQJXmBuuEYPi9ECAU/UFnNzeUp9VBQEBoFOLmFxWHNoQw6RWEocEQAh+QQFBQAAACwHAAAAGQARAAAEaRDICdZZNOvNDsvfBhBDdpwZgohBgE3nQaki0AYEjEqOGmqDlkEnAzBUjhrA0CoBYhLVSkm4SaAAWkahCFAWTU0A4RxzFWJnzXFWJJWb9pTihRu5dvghl+/7NQmBggo/fYKHCX8AiAmEEQAh+QQFBQAAACwOAAAAEgAYAAAEZXCwAaq9ODAMDOUAI17McYDhWA3mCYpb1RooXBktmsbt944BU6zCQCBQiwPB4jAihiCK86irTB20qvWp7Xq/FYV4TNWNz4oqWoEIgL0HX/eQSLi69boCikTkE2VVDAp5d1p0CW4RACH5BAUFAAAALA4AAAASAB4AAASAkBgCqr3YBIMXvkEIMsxXhcFFpiZqBaTXisBClibgAnd+ijYGq2I4HAamwXBgNHJ8BEbzgPNNjz7LwpnFDLvgLGJMdnw/5DRCrHaE3xbKm6FQwOt1xDnpwCvcJgcJMgEIeCYOCQlrF4YmBIoJVV2CCXZvCooHbwGRcAiKcmFUJhEAIfkEBQUAAAAsDwABABEAHwAABHsQyAkGoRivELInnOFlBjeM1BCiFBdcbMUtKQdTN0CUJru5NJQrYMh5VIFTTKJcOj2HqJQRhEqvqGuU+uw6AwgEwxkOO55lxIihoDjKY8pBoThPxmpAYi+hKzoeewkTdHkZghMIdCOIhIuHfBMOjxiNLR4KCW1ODAlxSxEAIfkEBQUAAAAsCAAOABgAEgAABGwQyEkrCDgbYvvMoOF5ILaNaIoGKroch9hacD3MFMHUBzMHiBtgwJMBFolDB4GoGGBCACKRcAAUWAmzOWJQExysQsJgWj0KqvKalTiYPhp1LBFTtp10Is6mT5gdVFx1bRN8FTsVCAqDOB9+KhEAIfkEBQUAAAAsAgASAB0ADgAABHgQyEmrBePS4bQdQZBdR5IcHmWEgUFQgWKaKbWwwSIhc4LonsXhBSCsQoOSScGQDJiWwOHQnAxWBIYJNXEoFCiEWDI9jCzESey7GwMM5doEwW4jJoypQQ743u1WcTV0CgFzbhJ5XClfHYd/EwZnHoYVDgiOfHKQNREAIfkEBQUAAAAsAAAPABkAEQAABGeQqUQruDjrW3vaYCZ5X2ie6EkcKaooTAsi7ytnTq046BBsNcTvItz4AotMwKZBIC6H6CVAJaCcT0CUBTgaTg5nTCu9GKiDEMPJg5YBBOpwlnVzLwtqyKnZagZWahoMB2M3GgsHSRsRACH5BAUFAAAALAEACAARABgAAARcMKR0gL34npkUyyCAcAmyhBijkGi2UW02VHFt33iu7yiDIDaD4/erEYGDlu/nuBAOJ9Dvc2EcDgFAYIuaXS3bbOh6MIC5IAP5Eh5fk2exC4tpgwZyiyFgvhEMBBEAIfkEBQUAAAAsAAACAA4AHQAABHMQyAnYoViSlFDGXBJ808Ep5KRwV8qEg+pRCOeoioKMwJK0Ekcu54h9AoghKgXIMZgAApQZcCCu2Ax2O6NUud2pmJcyHA4L0uDM/ljYDCnGfGakJQE5YH0wUBYBAUYfBIFkHwaBgxkDgX5lgXpHAXcpBIsRADs=" alt="loading">
<div id="result"></div>
<script>
var add = (function(){
var counter = 0;
return function(){
return ++counter;
}
})();
btn.onclick = function(){
img.style.display = 'inline-block';
btn.setAttribute('disabled','');
//建立xhr物件
var xhr;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
//非同步接受響應
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
img.style.display = 'none';
btn.removeAttribute('disabled');
var data = JSON.parse(xhr.responseText);
var sum = add() - 1;
if(sum < data.length){
result.innerHTML += data[sum];
}
}
}
}
//傳送請求
xhr.open('get','data.php',true);
xhr.send();
}
</script>
<?php
echo json_encode([1,2,3,4,5]);
?>