總括: 本文講解了ajax的歷史,工做原理以及優缺點,對XMLHttpRequest對象進行了詳細的講解,並使用原生js實現了一個ajax對象以方便平常開始使用。javascript
damonare的ajax庫:damonare的ajax庫php
博主博客地址:Damonare的我的博客html
古之立大事者,不唯有超世之才,亦必有堅忍不拔之志。前端
相信每一個前端程序員平常工做中都避免不了的工做就是和後端聯調,聯調天然就避免不了使用ajax
,但我相信,無論是使用jquery封裝的ajax
方法仍是使用vue的插件vue-resource
的程序員,真正對於ajax
有過深刻探究的並很少,咱們更多的是爲了使用而使用,至於它的原理每每由於即便不瞭解依舊能作出東西而懶得去看,咱們都被輪子們慣壞了。根據二八定律,即任何一組東西中,最重要的只佔其中一小部分,約20%,其他80%的儘管是多數,倒是次要的。因 此,若是想擠進那20%的行列,就要學到通常人學不到的深度,學到通常人學不了的東西。vue
好的,如今咱們從頭來講一下ajax
。java
在上世紀90年代,幾乎全部的網站都由HTML頁面實現,服務器處理每個用戶請求都須要從新加載網頁。形式是怎樣的呢?就好比說你在瀏覽器上登陸本身的微博帳號,填完了表單,點擊登陸按鈕,一次"完整"的HTTP請求就此觸發,服務器發現你的登陸密碼不對頭,立馬把網頁原本來本的返回給你,在用戶看來呢,就是一次從新加載的過程!用戶體驗極差!並且這個作法浪費了許多帶寬,由於在先後兩個頁面中的大部分HTML碼每每是相同的。因爲每次應用的溝通都須要向服務器發送請求,應用的迴應時間依賴於服務器的迴應時間。這致使了用戶界面的迴應比本機應用慢得多。jquery
到了2005年,google率先在它的應用(諸如google地圖、gmail)裏使用了ajax
技術,這才讓這項技術正式風靡開來。git
現在它的應用已經十分普遍:程序員
Ajax的工做原理至關於在用戶和服務器之間加了一箇中間層(ajax引擎),使用戶操做與服務器響應異步化。並非全部的用戶請求都提交給服務器,像—些數據驗證(好比判斷用戶是否輸入了數據)和數據處理(好比判斷用戶輸入數據是不是數字)等都交給Ajax引擎本身來作, 只有肯定須要從服務器讀取新數據時再由Ajax引擎代爲向服務器提交請求。把這些交給了Ajax引擎,用戶操做起來也就感受更加流暢了。github
AJAX最大優勢就是能在不刷新整個頁面的前提下與服務器通訊維護數據。這使得Web應用程序更爲迅捷地響應用戶交互,並避免了在網絡上發送那些沒有改變的信息,減小用戶等待時間,帶來很是好的用戶體驗。
2.異步與服務器通訊。
AJAX使用異步方式與服務器通訊,不須要打斷用戶的操做,具備更加迅速的響應能力。優化了Browser和Server之間的溝通,減小沒必要要的數據傳輸、時間及下降網絡上數據流量。
3.前端和後端負載平衡。
AJAX能夠把之前一些服務器負擔的工做轉嫁到客戶端,利用客戶端閒置的能力來處理,減輕服務器和帶寬的負擔,節約空間和寬帶租用成本。而且減輕服務器的負擔,AJAX的原則是「按需取數據」,能夠最大程度的減小冗餘請求和響應對服務器形成的負擔,提高站點性能。
4.基於標準被普遍支持。
AJAX基於標準化的並被普遍支持的技術,不須要下載瀏覽器插件或者小程序,但須要客戶容許JavaScript在瀏覽器上執行。隨着Ajax的成熟,一些簡化Ajax使用方法的程序庫也相繼問世。一樣,也出現了另外一種輔助程序設計的技術,爲那些不支持JavaScript的用戶提供替代功能。
5.界面與應用分離。
Ajax使WEB中的界面與應用分離(也能夠說是數據與呈現分離),有利於分工合做、減小非技術人員對頁面的修改形成的WEB應用程序錯誤、提升效率、也更加適用於如今的發佈系統。
對應用Ajax最主要的批評就是,它可能破壞瀏覽器的後退與加入收藏書籤功能。在動態更新頁面的狀況下,用戶沒法回到前一個頁面狀態,這是由於瀏覽器僅能記下歷史記錄中的靜態頁面。一個被完整讀入的頁面與一個已經被動態修改過的頁面之間的可能差異很是微妙;用戶一般都但願單擊後退按鈕,就可以取消他們的前一次操做,可是在Ajax應用程序中,卻沒法這樣作。不過開發者已想出了種種辦法來解決這個問題,HTML5 以前的方法大可能是在用戶單擊後退按鈕訪問歷史記錄時,經過建立或使用一個隱藏的IFRAME來重現頁面上的變動。(例如,當用戶在Google Maps中單擊後退時,它在一個隱藏的IFRAME中進行搜索,而後將搜索結果反映到Ajax元素上,以便將應用程序狀態恢復到當時的狀態)。
關於沒法將狀態加入收藏或書籤的問題,HTML5以前的一種方式是使用URL片段標識符(一般被稱爲錨點,即URL中#後面的部分)來保持追蹤,容許用戶回到指定的某個應用程序狀態。(許多瀏覽器容許JavaScript動態更新錨點,這使得Ajax應用程序可以在更新顯示內容的同時更新錨點。)HTML5 之後能夠直接操做瀏覽歷史,並以字符串形式存儲網頁狀態,將網頁加入網頁收藏夾或書籤時狀態會被隱形地保留。上述兩個方法也能夠同時解決沒法後退的問題。
2.AJAX的安全問題。
AJAX技術給用戶帶來很好的用戶體驗的同時也對IT企業帶來了新的安全威脅,Ajax技術就如同對企業數據創建了一個直接通道。這使得開發者在不經意間會暴露比之前更多的數據和服務器邏輯。Ajax的邏輯能夠對客戶端的安全掃描技術隱藏起來,容許黑客從遠端服務器上創建新的攻擊。還有Ajax也難以免一些已知的安全弱點,諸如跨站點腳步攻擊、SQL注入攻擊和基於Credentials的安全漏洞等等。
3.由於網絡延遲須要給用戶提供必要提示
進行Ajax開發時,網絡延遲——即用戶發出請求到服務器發出響應之間的間隔——須要慎重考慮。若是不給予用戶明確的迴應,沒有恰當的預讀數據,或者對XMLHttpRequest的不恰當處理,都會使用戶感到厭煩。一般的解決方案是,使用一個可視化的組件來告訴用戶系統正在進行後臺操做而且正在讀取數據和內容。
Ajax(Asynchronous JavaScript and XML)不是指一種單一的技術,而是有機地利用了一系列相關的技術。雖然其名稱包含XML,但實際上數據格式能夠由JSON代替,進一步減小數據量,造成所謂的AJAJ。爲了使用JavaScript向服務器發出 HTTP 請求,須要一個提供此功能的類的實例。這就是XMLHttpRequest的由來。這樣的類最初是在Internet Explorer中做爲一個名爲XMLHTTP的ActiveX對象引入的。而後,Mozilla,Safari和其餘瀏覽器,實現一個XMLHttpRequest類,支持Microsoft的原始ActiveX對象的方法和屬性。同時微軟也實現了XMLHttpRequest。
顯而易見XMLHttpRequest類是重中之重了。
一個JavaScript函數對象,當readyState屬性改變時會調用它。回調函數會在user interface線程中調用。
HTTP 請求的狀態.當一個 XMLHttpRequest 初次建立時,這個屬性的值從 0 開始,直到接收到完整的 HTTP 響應,這個值增長到 4。
5 個狀態中每個都有一個相關聯的非正式的名稱,下表列出了狀態、名稱和含義:
狀態 | 名稱 | 描述 |
---|---|---|
0 | Uninitialized | 初始化狀態。XMLHttpRequest 對象已建立或已被 abort() 方法重置。 |
1 | Open | open() 方法已調用,可是 send() 方法未調用。請求尚未被髮送。 |
2 | Sent | Send() 方法已調用,HTTP 請求已發送到 Web 服務器。未接收到響應。 |
3 | Receiving | 全部響應頭部都已經接收到。響應體開始接收但未完成。 |
4 | Loaded | HTTP 響應已經徹底接收。 |
readyState 的值不會遞減,除非當一個請求在處理過程當中的時候調用了 abort() 或 open() 方法。每次這個屬性的值增長的時候,都會觸發 onreadystatechange 事件句柄。
目前爲止爲服務器接收到的響應體(不包括頭部),或者若是尚未接收到數據的話,就是空字符串。
若是 readyState 小於 3,這個屬性就是一個空字符串。當 readyState 爲 3,這個屬性返回目前已經接收的響應部分。若是 readyState 爲 4,這個屬性保存了完整的響應體。
若是響應包含了爲響應體指定字符編碼的頭部,就使用該編碼。不然,假定使用 Unicode UTF-8。
對請求的響應,解析爲 XML 並做爲 Document 對象返回。
由服務器返回的 HTTP 狀態代碼,如 200 表示成功,而 404 表示 "Not Found" 錯誤。當 readyState 小於 3 的時候讀取這一屬性會致使一個異常。
這個屬性用名稱而不是數字指定了請求的 HTTP 的狀態代碼。也就是說,當狀態爲 200 的時候它是 "OK",當狀態爲 404 的時候它是 "Not Found"。和 status 屬性同樣,當 readyState 小於 3 的時候讀取這一屬性會致使一個異常。
取消當前響應,關閉鏈接而且結束任何未決的網絡活動。
這個方法把 XMLHttpRequest 對象重置爲 readyState 爲 0 的狀態,而且取消全部未決的網絡活動。例如,若是請求用了太長時間,並且響應再也不必要的時候,能夠調用這個方法。
把 HTTP 響應頭部做爲未解析的字符串返回。
若是 readyState 小於 3,這個方法返回 null。不然,它返回服務器發送的全部 HTTP 響應的頭部。頭部做爲單個的字符串返回,一行一個頭部。每行用換行符 "\r\n" 隔開。
返回指定的 HTTP 響應頭部的值。其參數是要返回的 HTTP 響應頭部的名稱。可使用任何大小寫來制定這個頭部名字,和響應頭部的比較是不區分大小寫的。
該方法的返回值是指定的 HTTP 響應頭部的值,若是沒有接收到這個頭部或者 readyState 小於 3 則爲空字符串。若是接收到多個有指定名稱的頭部,這個頭部的值被鏈接起來並返回,使用逗號和空格分隔開各個頭部的值。
初始化一個請求. 該方法用於JavaScript代碼中;若是是本地代碼, 使用 openRequest()
方法代替.
注意: 在一個已經激活的request下(已經調用open()或者openRequest()方法的request)再次調用這個方法至關於調用了abort()方法。
參數
method
請求所使用的HTTP方法; 例如 "GET", "POST", "PUT", "DELETE"等. 若是下個參數是非HTTP(S)的URL,則忽略該參數.
url
該請求所要訪問的URL
async
一個可選的布爾值參數,默認爲true,意味着是否執行異步操做,若是值爲false,則send()方法不會返回任何東西,直到接受到了服務器的返回數據。若是爲值爲true,一個對開發者透明的通知會發送到相關的事件監聽者。這個值必須是true,若是multipart 屬性是true,不然將會出現一個意外。
user
用戶名,可選參數,爲受權使用;默認參數爲空string.
password
密碼,可選參數,爲受權使用;默認參數爲空string.
發送 HTTP 請求,使用傳遞給 open() 方法的參數,以及傳遞給該方法的可選請求體。
向一個打開但未發送的請求設置或添加一個 HTTP 請求(設置請求頭)。
參數
header
將要被賦值的請求頭名稱
value
給指定的請求頭賦的值
下面是使用原生js寫的ajax:
var ajax = {}; ajax.httpRequest = function () { //判斷是否支持XMLHttpRequest對象 if (window.XMLHttpRequest) { return new XMLHttpRequest(); } //兼容IE瀏覽器 var versions = [ "MSXML2.XmlHttp.6.0", "MSXML2.XmlHttp.5.0", "MSXML2.XmlHttp.4.0", "MSXML2.XmlHttp.3.0", "MSXML2.XmlHttp.2.0", "Microsoft.XmlHttp" ]; //定義局部變量xhr,儲存IE瀏覽器的ActiveXObject對象 var xhr; for (var i = 0; i < versions.length; i++) { try { xhr = new ActiveXObject(versions[i]); break; } catch (e) { } } return xhr; }; ajax.send = function (url, callback, method, data, async) { //默認異步 if (async === undefined) { async = true; } var httpRequest = ajax.httpRequest(); //初始化HTTP請求 httpRequest.open(method, url, async); //onreadystatechange函數對象 httpRequest.onreadystatechange = function () { //readyState 的值等於4,從服務器拿到了數據 if (httpRequest.readyState == 4) { //回調服務器響應數據 callback(httpRequest.responseText) } }; if (method == 'POST') { //給指定的HTTP請求頭賦值 httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } //發送HTTP請求 httpRequest.send(data); }; //實現GET請求 ajax.get = function (url, data, callback, async) { var query = []; for (var key in data) { query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key])); } ajax.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, async) }; //實現POST請求 ajax.post = function (url, data, callback, async) { var query = []; for (var key in data) { query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key])); } ajax.send(url, callback, 'POST', query.join('&'), async) };
若是你使用jquery或是zepto很大部分是由於它的ajax兼容性高的緣故,不妨試試這個:damonare的ajax庫,喜歡給個star也是能夠的。
ajax技術對於整個web應用意義都是非凡的,僅以此篇致敬那些曾經奮鬥在一線爲了ajax技術的實現和普及作出工做的前輩們。