今天我來談談Ajax技術。web
Ajax是一種與服務器通訊而無需重載頁面的方法。數據能夠從服務器獲取或者發給服務器。json
Ajax和異步分不開,可是本文重點部分不是異步,而是對實現Ajax的技術進行總結。segmentfault
我簡要羅列一下幾種常見的Ajax技術:跨域
動態腳本注入和JSON-P瀏覽器
圖片信標(Beacons)安全
XMLHttpRequest(XHR)技術服務器
接下來我簡要談談我對這幾種技術的理解。異步
<!--more-->函數
以前的文章中談到,<script>
標籤做爲DOM的一部分,能夠由JavaScript調用DOM操做的接口動態建立。動態建立的<script>
元素能夠爲其設置src
屬性而且插入到DOM樹中。此時異步線程會並行的去加載src
資源,等到資源加載完成以後,其中的字符會當作JavaScript語句執行。網站
該技術是一個hack技術,它利用了瀏覽器的特性。該特性能夠實現「無阻塞加載腳本」技術。更多細節能夠移步:無阻塞加載腳本的理解。
除了在頁面初始化的時候可使用動態腳本注入,Ajax技術也可使用動態腳本注入的技術實現。動態腳本注入能夠從服務器中請求數據。
首先咱們須要將待請求數據的細節放在src
中。由於src
對應一個url,瀏覽器會將這個url做爲GET請求發往相應的服務器,因此咱們將請求數據做爲查詢字符串寫入src
。
服務器在收到請求後,會返回數據。可是這個數據必須以一段JavaScript腳本的形式返回。緣由是瀏覽器收到響應數據後會將其當作JavaScript腳本執行。
也就是說,假設響應數據若是隻是簡單的xml或者json數據,對於動態腳本注入來講,沒有任何意義。
所以服務器收到動態腳本注入中的GET請求時,須要返回一個約定好的表示JavaScript腳本的字符串。這段腳本還須要處理瀏覽器端須要的數據,好比:
dosomething([{"x": 1, "y": "haha"}]);
這段字符串返回以後就會被執行。其中dosomething
就是約定好的一個回調函數名。這個回調函數已經在以前的腳本中定義好。
另外,咱們還能夠將回調函數名稱做爲查詢字符串傳入,這樣服務器就能夠動態的將回調函數做爲響應數據中的一部分返回。
dosomething
中的參數一個JSON數據,可是它在返回以後,會被當作JavaScript對象執行。因爲這種特性,使用JSON的動態腳本注入又能夠稱做所謂的「JSON-P」。
該技術還有兩個注意點:
動態腳本注入技術能夠跨域訪問,不一樣域中返回的腳本可能截獲網站數據,致使安全問題,所以要當心使用。
動態腳本注入技術不能發送POST等非GET請求。然而,有些瀏覽器對GET請求有諸多限制(好比url字符數的限制),所以須要POST請求的Ajax,請考慮其餘方法。
Beacons技術很適合向服務器發送數據。
和上面的動態腳本注入相似,Beacons可使用特定的DOM元素,利用src
屬性向服務器發送數據,可是不須要服務器返回數據。
咱們可使用一個Image
對象,設置src
以後,該請求會從服務器返回一個圖片(通常是一個1*1的透明圖片)。這是最經常使用的方法。
var url = "...."; var params = [ "..", ".." ]; var img = new Image(); img.src = url + '?' + params.join('&');
若是響應中不須要任何數據,注意須要服務器設置狀態碼爲204 No Content
。
若是須要必定的消息返回,咱們能夠用一種變通的手法:設置返回圖片的寬度,不一樣的寬度表明不一樣的信息。這些信息能夠在Image
對象的onload
事件中監聽。
img.onload = function(){ if (this.width === 1){ // ... } else if (this.width === 2){ // ... } // else if ... }
和動態腳本注入相似,Beacons技術也有可跨域和沒法發送非GET請求的問題。
另外,也能夠利用<iframe>
標籤來作相似的操做。
目前Ajax使用最多的技術手段就是利用XMLHttpRequest
技術。
XMLHttpRequest
是一個特殊的構造函數,這個構造函數不在ECMA標準內,可是各大瀏覽器對其均支持良好。
直接上代碼:
var xhr = new XMLHttpRequest(); var url = '...'; var data; // 接受響應主體 var header; // 接受響應頭 var status; // 接收狀態碼 var statusText; // 接收狀態信息 xhr.onreadystatechange = function(){ // 監聽readyState變化 if (xhr.readyState === 4){ // 該值爲4,代表響應結束 data = xhr.responseText; // 獲取響應主體 // or: data = xhr.responseXML; ... headers = xhr.getAllResponseHeaders(); // 獲取響應頭 status = xhr.status; // 獲取狀態碼 statusText = xhr.statusText; //獲取狀態信息 // do something... } } xhr.open('GET', url, true); // 開啓一個請求,true表示異步響應 xhr.setRequestHeader('..', '..'); // 設置請求頭 xhr.send(null); // 開始發送,參數是請求主體(用於POST請求)
XMLHttpRequest
支持GET和POST請求,而且能夠輕鬆設置請求主體和部分請求頭,也能夠獲取響應主體和響應頭。雖然名稱叫XMLHttpRequest
,可是事實上它支持各類不一樣的數據格式如JSON、HTML等。
可是注意,該技術是不能跨域訪問的,除非web服務器設置了容許跨域訪問策略。
另外一個值得注意的地方就是:readyState
的值爲4
,代表響應結束,可是咱們也能夠監聽其值爲3
的狀況,該值代表響應正在進行,此時能夠獲取部分響應主體。 readyState
的值爲0
、1
和2
分別表示open()
還沒有調用、open()
已調用,和接收到頭信息。這些用途相對較小。
更多詳情,請參見MDN中關於XMLHttpRequest的解釋:連接