jQuery源碼分析系列(37) : Ajax 總結

來源:互聯網
上載者:User

標籤:des   style   blog   http   color   get   

 

綜合前面的分析,我們總結如下3大塊:

  • jQuery1.5以後,AJAX模組提供了三個新的方法用於管理、擴充AJAX請求
    1. 前置過濾器 jQuery. ajaxPrefilter
    2. 請求分發器 jQuery. ajaxTransport
    3. 類型轉換器 ajaxConvert
  • 為了整體性與擴充性考慮,把整個結構通過Deferred實現非同步鏈式模型,Promise對象可以輕易的綁定成功、失敗、進行中三種狀態的回呼函數,然後通過在狀態代碼在來回調不同的函數就行了
  • 出於同源策略考慮,存在跨域問題,所以ajax內部的處理總的來分2大塊
    1. 基於XMLHttpRequest的ajax請求
    2. 基於script的jsonp跨域請求

 

引入Deferred統一回調體系

jQuery的鏈式方法是大是通過返回this的引用,但是ajax的鏈式不是那麼簡單的,因為ajax可以非同步作業,所以返回的是一個非同步模型對象Promise

當然如果只是deferred = jQuery.Deferred() 返回這個對象也是沒意義的,因為無法關聯到實際的資料

所以jquery內部構建了一個增強版的jqXHR對象,除了混入Promise模型,還增強了一些方法與介面

jqXHR 擴充基本的方法與介面

jqXHR = {    // 準備狀態    readyState: 0,    // Builds headers hashtable if needed    // 如果需要,建立一個回應標頭參數的表    getResponseHeader: function(key) {        var match;        // 如果狀態為2,狀態2表示ajax完成        if (state === 2) {            // 如果沒有相應頭            if (!responseHeaders) {                // 相應頭設空                responseHeaders = {};                // 組裝相應頭                while ((match = rheaders.exec(responseHeadersString))) {                    responseHeaders[match[1].toLowerCase()] = match[2];                }            }            // 回應標頭對應的key的值            match = responseHeaders[key.toLowerCase()];        }        return match == null ? null : match;    },    // Raw string    // 返迴響應頭字串    getAllResponseHeaders: function() {        // 看看是否接收到了,接收到直接返回,否則為null        return state === 2 ? responseHeadersString : null;    },    // Caches the header    // 佈建要求頭    setRequestHeader: function(name, value) {        var lname = name.toLowerCase();        if (!state) {            // 如果requestHeadersNames[ lname ]不為空白,            // 則requestHeadersNames[ lname ]不變,name設定為該值            // 否則,requestHeadersNames[ lname ]不空,            // 則requestHeadersNames[ lname ]設定為name,            // 該映射關係用於避免使用者大小寫書寫錯誤之類的問題,容錯處理            name = requestHeadersNames[lname] = requestHeadersNames[lname] || name;            //現在的name是對的,或者是第一次設定這個name,不需要容錯            //佈建要求頭對應值            requestHeaders[name] = value;        }        return this;    },    // Overrides response content-type header    // 重寫相應頭content-type    overrideMimeType: function(type) {        if (!state) {            s.mimeType = type;        }        return this;    },    // Status-dependent callbacks    // 對應狀態的回呼函數集    statusCode: function(map) {        var code;        if (map) {            //如果狀態小於2,表示舊的回調可能還沒有用到            if (state < 2) {                for (code in map) {                    // Lazy-add the new callback in a way that preserves old ones                    //  用類似鏈表的方式添加,以保證舊的回調依然存在                    statusCode[code] = [statusCode[code], map[code]];                }            } else {                // Execute the appropriate callbacks                // 無論Deferred成功還是失敗都執行目前狀態回調                jqXHR.always(map[jqXHR.status]);            }        }        return this    },    // Cancel the request    abort: function(statusText) {        var finalText = statusText || strAbort;        if (transport) {            transport.abort(finalText);        }        done(0, finalText);        return this;    }};

看看我們ajax的寫法

$.ajax({    url: "php.html",    context: document.body,    complete: function() {        console.log(this)    }}).done(function() {    console.log(this)});

鏈式了一個done方法,done是Promise模型中的成功回調,因為ajax返回的是jqXHR對象

所以jqXHR就需要混入Promise模型

deferred.promise(jqXHR).complete = completeDeferred.add; jqXHR.success = jqXHR.done; jqXHR.error   = jqXHR.fail;

看ajax源碼前需要瞭解回到隊列與Deferreds

jqXHR混入了Promise模型處理,當然只能讀防止修改,之外還增加了一個complete的的回調隊列

具體怎麼使用,看後面

for (i in {    success  : 1,    error    : 1,    complete : 1}) {    jqXHR[i](s[i]);}

很巧妙的一個處理,把使用者設定檔中的回呼函數給註冊到這個jqXHR的回調體系中

所以就把所有的有關回調都綁定到了jqXHR對象上了

 

ajax提供3種事件通知介面

1 提供全域事件,外部的視圖可以根據ajax狀態進行改變

2 提供內部事件介面,根據流程做相對應的處理

3 提供鏈式事件介面,通過Promise實現

當ajax開始時類比全域事件,ajaxStart

這裡主要利用了jQuery.event.trigger和jQuery.fn.trigger類比發事件

if (fireGlobals && jQuery.active++ === 0) {     // 則通過jQuery.event.trigger類比觸發    jQuery.event.trigger("ajaxStart");}

 

ajax發送訊息,觸發ajaxSend

/** * 全域事件ajaxSend * 如果需要,對特定對象觸發全域事件ajaxSend */if (fireGlobals) {    globalEventContext.trigger("ajaxSend", [jqXHR, s]);}

 

結束時觸發ajaxSuccess或ajaxError,再出發ajaxComplete,如果全部ajax結束則觸發ajaxStop。

if (fireGlobals) {                globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]);            }            // Complete            completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);            if (fireGlobals) {                globalEventContext.trigger("ajaxComplete", [jqXHR, s]);                // Handle the global AJAX counter                if (!(--jQuery.active)) {                    jQuery.event.trigger("ajaxStop");                }            }

 

關於快取資料

如果我們的請求為GET的時候的處理,使用者通過data自訂了一些資料,那麼這些資料只能通過拼接成url傳遞給服務端

我們需要通過給地址附加參數_=xxx來避免緩衝

if (s.cache === false) {    s.url = rts.test(cacheURL) ?    // If there is already a ‘_‘ parameter, set its value    cacheURL.replace(rts, "$1_=" + ajax_nonce++) :    // Otherwise add one to the end    cacheURL + (ajax_rquery.test(cacheURL) ? "&" : "?") + "_=" + ajax_nonce++;}

 

從jQuery 1.5開始$.ajax() 返回XMLHttpRequest(jqXHR)對象,該對象是瀏覽器的原生的XMLHttpRequest對象的一個超集。

例如,它包含responseTextresponseXML屬性,以及一個getResponseHeader()方法。

當傳輸機制不是是XMLHttpRequest時(例如,一個JSONP請求指令碼,返回一個指令碼 tag 時),jqXHR對象儘可能的類比原生的XHR功能。

從jQuery 1.5.1開始jqXHR對象還包含了overrideMimeType方法 (它在jQuery 1.4.x中是有效,但是在jQuery 1.5中暫時的被移除)。

.overrideMimeType() 方法可能用在beforeSend()的回呼函數中,

例如,修改響應的Content-Type資訊頭:

$.ajax({  url: "http://fiddle.jshell.net/favicon.png",  beforeSend: function ( xhr ) {    xhr.overrideMimeType("text/plain; charset=x-user-defined");  }}).done(function ( data ) {  if( console && console.log ) {    console.log("Sample of data:", data.slice(0, 100));  }});

從 jQuery 1.5 開始,$.ajax()返回的jqXHR對象 實現了 Promise 介面, 使它擁有了 Promise 的所有屬性,方法和行為。(見Deferred object擷取更多資訊)。

為了讓回呼函數的名字統一,便於在$.ajax()中使用。jqXHR也提供.error() .success().complete()方法。這些方法都帶有一個參數,該參數是一個函數,此函數在 $.ajax()請求結束時被調用,並且這個函數接收的參數,與調用 $.ajax()函數時的參數是一致。這將允許你在一次請求時,對多個回呼函數進行賦值,甚至允許你在請求已經完成後,對回呼函數進行賦值(如果該請求已經完成,則回呼函數會被立刻調用)。

更多的更多大家還是仔細參考API吧

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.