AJAX的底層實現都是瀏覽器提供的,因此任何基於api上面的框架或者庫,都只是說對於功能的靈活與兼容維護性作出最優的擴展php
ajax請求的流程:html
一、經過 new XMLHttpRequest 或其它的形式(指IE)生成ajax的對象xhr。 ajax
二、經過xhr.open(type, url, async, username, password)的形式創建一個鏈接。 編程
三、經過setRequestHeader設定xhr的請求頭部(request header)。 json
四、經過send(data)請求服務器端的數據。api
五、執行在xhr上註冊的onreadystatechange回調處理返回數據。跨域
這幾步之中,promise
咱們開發者可能會遇到的問題瀏覽器
1 跨域緩存
2 json的格式
3 dataType
4 AJAX亂碼問題
5 頁面緩存
6 狀態的跟蹤
7 不一樣平臺兼容
jQuery主要就是解決上面這問題,以後就在這個基礎之上進行擴展
jQuery2.0.3版的Ajax部分源碼大概有1200多行,主要針對ajax的操做進行了一些擴展,使之更加靈活
jQuery在1.5中對AJAX模塊的重寫,增長了幾個新的概念
AJAX模塊提供了三個新的方法用於管理、擴展AJAX請求,分別是:
除此以後還重寫了整個異步隊列處理,加入了deferred,能夠將任務完成的處理方式與任務自己解耦合,使用deferreds對象,多個回調函數能夠被綁定在任務完成時執行,甚至能夠在任務完成後綁定這些回調函數。這些任務能夠是異步的,也能夠是同步的。
好比
1.鏈式反饋done與fail
$.ajax({ url: "script.php", type: "POST", data: { id: menuId }, dataType: "html" }).done(function(msg) { $("#log").html(msg); }).fail(function(jqXHR, textStatus) { alert("Request failed: " + textStatus); });
2.分離異步與同步處理
var aajax = $.ajax({ url: "script.php", type: "POST", data: { id: menuId }, dataType: "html" }).fail(function(jqXHR, textStatus) { alert("Request failed: " + textStatus); }); //同步還在執行代碼,這個函數有可能在AJAX結束前調用 dosomething() //異步還在等在成功響應 aajax.done(function(msg) { $("#log").html(msg); })
再也不被限制到只有一個成功,失敗或者完成的回調函數了。相反這些隨時被添加的回調函數被放置在一個先進先出的隊列中。
3.同時執行多個ajax請求
function ajax1() { return $.get('1.htm'); } function ajax2() { return $.get('2.htm'); } $.when(ajax1(), ajax2()) .then(function() { //成功 }) .fail(function() { //失敗 });
這個比較複雜一點,原理其實就是$.get返回的是一個deferred對象,每一個jQuery的AJAX方法返回值都包含一個promise函數,用來跟蹤異步請求。Promise函數的返回值是deferred對象的一個只讀視圖
Deferreds經過檢測對象中是否存在promise()函數來判斷當前對象是否可觀察。$.when()會等待全部的AJAX請求結束,而後調用經過 .then(), .fail()註冊的回調函數(具體調用哪些回調函數取決於任務的結束狀態)。這些回調函數會按照他們的註冊順序執行
顯而易見,deferred對象就是jQuery的回調函數解決方案,它解決了如何處理耗時操做的問題,對那些操做提供了更好的控制,以及統一的編程接口
說白了無非就是在ajax的實現邏輯中,把deferred對象給摻進去了,使之整個ajax方法變成了一個deferred對象
在ajax方法中返回的是jqXHR一個包裝對象,在這個對象裏面混入了全部實現方法
ajax: function(url, options) { //......... return jqXHR }
從jQuery 1.5開始,$.ajax()
返回XMLHttpRequest(jqXHR)對象,該對象是瀏覽器的原生的XMLHttpRequest對象的一個超集。例如,它包含responseText
和responseXML
屬性,以及一個getResponseHeader()
方法。當傳輸機制不是是XMLHttpRequest時(例如,一個JSONP請求腳本,返回一個腳本 tag 時),jqXHR對象儘量的模擬原生的XHR功能。
從jQuery 1.5.1開始, jqXHR
對象還包含了overrideMimeType
方法 (它在jQuery 1.4.x中是有效的,可是在jQuery 1.5中暫時的被移除)。.overrideMimeType()
方法可能用在beforeSend()
的回調函數中,例如,修改響應的Content-Type信息頭:
爲了讓回調函數的名字統一,便於在$.ajax()
中使用。jqXHR也提供.error()
.success()
和.complete()
方法。這些方法都帶有一個參數,該參數是一個函數,此函數在 $.ajax()
請求結束時被調用,而且這個函數接收的參數,與調用 $.ajax()
函數時的參數是一致。這將容許你在一次請求時,對多個回調函數進行賦值,甚至容許你在請求已經完成後,對回調函數進行賦值(若是該請求已經完成,則回調函數會被馬上調用)。
爲了向後兼容XMLHttpRequest
,一jqXHR
對象將公開下列屬性和方法:
readyState
status
statusText
responseXML
and/or responseText
當底層的請求分別做出XML和/或文本響應setRequestHeader(name, value)
從標準出發,經過替換舊的值爲新的值,而不是替換的新值到舊值getAllResponseHeaders()
getResponseHeader()
abort()
那麼在對包裝器jqXHR對象作混入以前,咱們要先準備好
1 異步隊列deferred
2 回調隊列Callbacks
// Deferreds deferred = jQuery.Deferred(), /** * 全部的回調隊列,無論任什麼時候候增長的回調保證只觸發一次 * @type {[type]} */ completeDeferred = jQuery.Callbacks("once memory"),
給jqXHR擴充添加promise的屬性和方法,而後添加complete方法,這裏用的是回調列表的add方法(即添加回調)
deferred.promise(jqXHR).complete = completeDeferred.add;
此時的jqXHR就具備了promise的一些特性了與callback的回調列隊了
固然這裏有個重點,返回了一個只讀的deferred對象
若是返回完整的deferred對象,那麼外部程序就能隨意的觸發deferred對象的回調函數,頗有可能在AJAX請求結束前就觸發了回調函數(resolve),這就是與AJAX自己的邏輯相違背了。
因此爲了不不經意間改變任務的內部流程,咱們應該只返回deferred的只讀版本 deferred.promise()
而後把對應的done與fail改爲別名success與error
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
咱們還須要把用戶自定的內部回調函數給註冊到jqXHR對象上
// 增長回調隊列 for (i in { success : 1, error : 1, complete : 1 }) { /** * 把參數的回調函數註冊到內部jqXHR對象上,實現統一調用 * 給ajax對象註冊 回調函數add * deferred返回complete,error外部捕獲 */ jqXHR[i](s[i]); }
jqXHR.success(s.success) -> jqXHR.done -> jQuery.Callbacks("once memory")
jqXHR.error(s.error) -> jqXHR.fail -> jQuery.Callbacks("once memory")
jqXHR.complete(s.complete) -> jQuery.Callbacks("once memory").add(s.success)
待續....