你真的懂 ajax 嗎?


前言

總括: 本文講解了ajax的歷史,工作原理以及優缺點,對XMLHttpRequest對象進行了詳細的講解,並使用原生js實現了一個ajax對象以方便日常開始使用。

古之立大事者,不惟有超世之才,亦必有堅忍不拔之志。

正文

相信每個前端程序員日常工作中都避免不了的工作就是和后端聯調,聯調自然就避免不了使用ajax,但我相信,不管是使用jquery封裝的ajax方法還是使用vue的插件vue-resource的程序員,真正對於ajax有過深入探究的並不多,我們更多的是為了使用而使用,至於它的原理往往因為即使不了解依舊能做出東西而懶得去看,我們都被輪子們慣壞了。根據二八定律,即任何一組東西中,最重要的只占其中一小部分,約20%,其余80%的盡管是多數,卻是次要的。因 此,如果想擠進那20%的行列,就要學到一般人學不到的深度,學到一般人學不了的東西。

好的,現在我們從頭來說一下ajax

Ajax簡介

在上世紀90年代,幾乎所有的網站都由HTML頁面實現,服務器處理每一個用戶請求都需要重新加載網頁。形式是怎樣的呢?就比如說你在瀏覽器上登錄自己的微博賬號,填完了表單,點擊登錄按鈕,一次"完整"的HTTP請求就此觸發,服務器發現你的登錄密碼不對頭,立馬把網頁原原本本的返回給你,在用戶看來呢,就是一次重新加載的過程!用戶體驗極差!而且這個做法浪費了許多帶寬,因為在前后兩個頁面中的大部分HTML碼往往是相同的。由於每次應用的溝通都需要向服務器發送請求,應用的回應時間依賴於服務器的回應時間。這導致了用戶界面的回應比本機應用慢得多。

到了2005年,google率先在它的應用(諸如google地圖、gmail)里使用了ajax技術,這才讓這項技術正式風靡開來。

如今它的應用已經十分廣泛:

Ajax工作原理

Ajax的工作原理相當於在用戶和服務器之間加了一個中間層(ajax引擎),使用戶操作與服務器響應異步化。並不是所有的用戶請求都提交給服務器,像—些數據驗證(比如判斷用戶是否輸入了數據)和數據處理(比如判斷用戶輸入數據是否是數字)等都交給Ajax引擎自己來做, 只有確定需要從服務器讀取新數據時再由Ajax引擎代為向服務器提交請求。把這些交給了Ajax引擎,用戶操作起來也就感覺更加流暢了。

Ajax優缺點

Ajax的優點

1.無刷新更新數據。

AJAX最大優點就是能在不刷新整個頁面的前提下與服務器通信維護數據。這使得Web應用程序更為迅捷地響應用戶交互,並避免了在網絡上發送那些沒有改變的信息,減少用戶等待時間,帶來非常好的用戶體驗。

2.異步與服務器通信。

AJAX使用異步方式與服務器通信,不需要打斷用戶的操作,具有更加迅速的響應能力。優化了Browser和Server之間的溝通,減少不必要的數據傳輸、時間及降低網絡上數據流量。

3.前端和后端負載平衡。

AJAX可以把以前一些服務器負擔的工作轉嫁到客戶端,利用客戶端閑置的能力來處理,減輕服務器和帶寬的負擔,節約空間和寬帶租用成本。並且減輕服務器的負擔,AJAX的原則是“按需取數據”,可以最大程度的減少冗余請求和響應對服務器造成的負擔,提升站點性能。

4.基於標准被廣泛支持。

AJAX基於標准化的並被廣泛支持的技術,不需要下載瀏覽器插件或者小程序,但需要客戶允許JavaScript在瀏覽器上執行。隨着Ajax的成熟,一些簡化Ajax使用方法的程序庫也相繼問世。同樣,也出現了另一種輔助程序設計的技術,為那些不支持JavaScript的用戶提供替代功能。

5.界面與應用分離。

Ajax使WEB中的界面與應用分離(也可以說是數據與呈現分離),有利於分工合作、減少非技術人員對頁面的修改造成的WEB應用程序錯誤、提高效率、也更加適用於現在的發布系統。

Ajax缺點

1.AjAX干掉了Back和加入收藏書簽功能,即對瀏覽器機制的破壞。

對應用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的不恰當處理,都會使用戶感到厭煩。通常的解決方案是,使用一個可視化的組件來告訴用戶系統正在進行后台操作並且正在讀取數據和內容。

XMLhttpRequest介紹

Ajax(Asynchronous JavaScript and XML)不是指一種單一的技術,而是有機地利用了一系列相關的技術。雖然其名稱包含XML,但實際上數據格式可以由JSON代替,進一步減少數據量,形成所謂的AJAJ。為了使用JavaScript向服務器發出 HTTP 請求,需要一個提供此功能的類的實例。這就是XMLHttpRequest的由來。這樣的類最初是在Internet Explorer中作為一個名為XMLHTTP的ActiveX對象引入的。然后,Mozilla,Safari和其他瀏覽器,實現一個XMLHttpRequest類,支持Microsoft的原始ActiveX對象的方法和屬性。同時微軟也實現了XMLHttpRequest。

顯而易見XMLHttpRequest類是重中之重了。

XMLhttpRequest屬性

onreadystatechange

一個JavaScript函數對象,當readyState屬性改變時會調用它。回調函數會在user interface線程中調用。

readyState

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 事件句柄。

responseText

目前為止為服務器接收到的響應體(不包括頭部),或者如果還沒有接收到數據的話,就是空字符串。

如果 readyState 小於 3,這個屬性就是一個空字符串。當 readyState 為 3,這個屬性返回目前已經接收的響應部分。如果 readyState 為 4,這個屬性保存了完整的響應體。

如果響應包含了為響應體指定字符編碼的頭部,就使用該編碼。否則,假定使用 Unicode UTF-8。

responseXML

對請求的響應,解析為 XML 並作為 Document 對象返回。

status

由服務器返回的 HTTP 狀態代碼,如 200 表示成功,而 404 表示 "Not Found" 錯誤。當 readyState 小於 3 的時候讀取這一屬性會導致一個異常。

statusText

這個屬性用名稱而不是數字指定了請求的 HTTP 的狀態代碼。也就是說,當狀態為 200 的時候它是 "OK",當狀態為 404 的時候它是 "Not Found"。和 status 屬性一樣,當 readyState 小於 3 的時候讀取這一屬性會導致一個異常。

XMLHttpRequest方法

abort()

取消當前響應,關閉連接並且結束任何未決的網絡活動。

這個方法把 XMLHttpRequest 對象重置為 readyState 為 0 的狀態,並且取消所有未決的網絡活動。例如,如果請求用了太長時間,而且響應不再必要的時候,可以調用這個方法。

getAllResponseHeaders()

把 HTTP 響應頭部作為未解析的字符串返回。

如果 readyState 小於 3,這個方法返回 null。否則,它返回服務器發送的所有 HTTP 響應的頭部。頭部作為單個的字符串返回,一行一個頭部。每行用換行符 "\r\n" 隔開。

getResponseHeader()

返回指定的 HTTP 響應頭部的值。其參數是要返回的 HTTP 響應頭部的名稱。可以使用任何大小寫來制定這個頭部名字,和響應頭部的比較是不區分大小寫的。

該方法的返回值是指定的 HTTP 響應頭部的值,如果沒有接收到這個頭部或者 readyState 小於 3 則為空字符串。如果接收到多個有指定名稱的頭部,這個頭部的值被連接起來並返回,使用逗號和空格分隔開各個頭部的值。

open()

初始化一個請求. 該方法用於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.

send()

發送 HTTP 請求,使用傳遞給 open() 方法的參數,以及傳遞給該方法的可選請求體。

setRequestHeader()

向一個打開但未發送的請求設置或添加一個 HTTP 請求(設置請求頭)。

參數

  • header

    將要被賦值的請求頭名稱

  • value

    給指定的請求頭賦的值

Ajax原生js實現

下面是使用原生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技術的實現和普及做出工作的前輩們。

參考文章


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM