jQuery源碼分析系列(31) : Ajax deferred實現

來源:互聯網
上載者:User

AJAX的底層實現都是瀏覽器提供的,所以任何基於api上面的架構或者庫,都只是說對於功能的靈活與相容維護性做出最優的擴充 ajax請求的流程: 1、通過 new XMLHttpRequest 或其它的形式(指IE)產生ajax的對象xhr。   2、通過xhr.open(type, url, async, username, password)的形式建立一個串連。  3、通過setRequestHeader設定xhr的要求標頭部(request header)。   4、通過send(data)請求伺服器端的資料。 5、執行在xhr上註冊的onreadystatechange回調處理返回資料。 這幾步之中, 我們開發人員可能會遇到的問題 1 跨域 2 json的格式 3 dataType 4 AJAX亂碼問題 5 頁面緩衝 6 狀態的跟蹤 7 不同平台相容 jQuery主要就是解決上面這問題,之後就在這個基礎之上進行擴充   jQuery2.0.3版的Ajax部分源碼大概有1200多行,主要針對ajax的操作進行了一些擴充,使之更加靈活 jQuery在1.5中對AJAX模組的重寫,增加了幾個新的概念 AJAX模組提供了三個新的方法用於管理、擴充AJAX請求,分別是: 前置過濾器 jQuery. ajaxPrefilter請求分發器 jQuery. ajaxTransport,類型轉換器 ajaxConvert除此之後還重寫了整個非同步隊列處理,加入了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的回呼函數解決方案,它解決了如何處理耗時操作的問題,對那些操作提供了更好的控制,以及統一的編程介面   jqXHR 對象 說白了無非就是在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對象將公開下列屬性和方法: readyStatestatusstatusTextresponseXML and/or responseText 當底層的請求分別作出XML和/或文本響應setRequestHeader(name, value) 從標準出發,通過替換舊的值為新的值,而不是替換的新值到舊值getAllResponseHeaders()getResponseHeader()abort()    那麼在對封裝器jqXHR對象做混入之前,我們要先準備好 1 非同步隊列deferred 2 回調隊列Callbacks 複製代碼// Deferredsdeferred = jQuery.Deferred(), /** * 所有的回調隊列,不管任何時候增加的回調保證只觸發一次 * @type {[type]} */completeDeferred = jQuery.Callbacks("once memory"),複製代碼  給jqXHR擴充添加promise的屬性和方法,然後添加complete方法,這裡用的是回調列表的add方法(即添加回調) deferred.promise(jqXHR).complete = completeDeferred.add;image 此時的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)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.