jQuery源碼分析系列(33) : AJAX中的前置過濾器和請求分發器


jQuery1.5以后,AJAX模塊提供了三個新的方法用於管理、擴展AJAX請求,分別是:

1.前置過濾器 jQuery. ajaxPrefilter

2.請求分發器 jQuery. ajaxTransport,

3.類型轉換器 ajaxConvert

源碼結構:

jQuery.extend({

    /**
     * 前置過濾器
     * @type {[type]}
     */
    ajaxPrefilter: addToPrefiltersOrTransports(prefilters),

    /**
     * 請求分發器
     * @type {[type]}
     */
    ajaxTransport: addToPrefiltersOrTransports(transports),

    
     ...........................
});

可見這2個方法是通過私有方法addToPrefiltersOrTransports通過curry手段構造的,分別是保持了prefilters與transports的引用

 


來個簡單的模擬這個結構

var prefilters = 2;

var addToPrefiltersOrTransports = function(prefilters) {
    return function(b) {
        return prefilters + b;
    }
}

var ajaxPrefilter = addToPrefiltersOrTransports(prefilters)

ajaxPrefilter(1) //3

可見ajaxPrefilter就維持了addToPrefiltersOrTransports返回函數的引用了,這種就是閉包的手法了,這也是JS的開發人員都需要掌握的

好處就是合並多個參數,當然因為維持引用代價就是一點點性能消耗

 

當然jQuery不是傳遞的簡單類型處理,還可以傳遞的一個引用類型的回調函數,所以針對ajaxPrefilter方法放閉包構件就需要做一些處理了

填充prefilters處理器

var prefilters = {};

var addToPrefiltersOrTransports = function(structure) {

    return function(func) {
        structure['*'] = func;
    }
}

var ajaxPrefilter = addToPrefiltersOrTransports(prefilters)


ajaxPrefilter(function(options){
    return {
        send:function(){

        },
        callback:function(){

        }
    }
})

其實說白了就是把對應的方法制作能函數的形式填充到prefilters或者transports對應的處理包裝對象中

要用的時候直接執行,每個函數都保持着各自的引用

這種寫法的好處自然是靈活,易維護,減少代碼量

還有我們經常的使用的,jQuery的代碼很簡練,比如合並多個方法的創建等等

jQuery.each([
        "tabIndex",
        "readOnly",
        "maxLength",
        "contentEditable"
    ], function() {
        jQuery.propFix[this.toLowerCase()] = this;
    });

 

所以此時的prefilters中的結構就是

prefilters = {
        '*': function() {
            return {
                send: function() {

                },
                callback: function() {

                }
            }
        }
    }

 


回歸重點,那么引入ajaxPrefilter與ajaxTransport的作用是干嘛?

前置過濾器和請求分發器在執行時,分別遍歷內部變量prefilters和transports,這兩個變量在jQuery加載完畢后立即初始化,從過閉包的方法填充這個2個對象

 

ajaxPrefilter與ajaxTransport都是通過inspectPrefiltersOrTransports構建器

prefilters中的前置過濾器在請求發送之前、設置請求參數的過程中被調用,調用prefilters的是函數inspectPrefiltersOrTransports;

巧妙的是,transports中的請求分發器在大部分參數設置完成后,也通過函數inspectPrefiltersOrTransports取到與請求類型匹配的請求分發器:

function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {

    var inspected = {},
        seekingTransport = (structure === transports);

    function inspect(dataType) {
        var selected;
        inspected[dataType] = true;
        jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) {
            var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
            if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
                options.dataTypes.unshift(dataTypeOrTransport);
                inspect(dataTypeOrTransport);
                return false;
            } else if (seekingTransport) {
                return !(selected = dataTypeOrTransport);
            }
        });
        return selected;
    }

    return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
}

遍歷structure[dataType]數組,並執行回調
prefilterOrFactory為函數數組元素
執行該函數如果返回的結果dataTypeOrTransport是字符串且時prefilters且沒有被inspected過
就給options.dataTypes數組頭部添加該字符串
繼續遞歸dataTypeOrTransport(當我們使用json/jsonp的時候會返回“script”,於是會執行“script”相關的回調)
如果是transport就返回dataTypeOrTransport的假結果

 


前置過濾器 prefilters

簡單的說就是一種hack的做法,只是說比起事件的那種hack寫的手法實現更為高明

我們可以看看針對prefilters的方法其實就是dataType為 script,json,jsonp的處理

當我們動態加載腳本文件比如

$.ajax({
    type     : "GET",
    url      : "test.js",
    dataType : "script"
});

所以在inspectPrefiltersOrTransports方法中prefilters[script]能找到對應的處理方法,所以就會執行

例如script的hack,要強制加上處理緩存的特殊情況和crossDomain

因為設置script的前置過濾器,script並不一定意思着跨域

跨域未被禁用,強制類型為GET,不觸發全局時間

jQuery.ajaxPrefilter("script", function(s) {
    if (s.cache === undefined) {
        s.cache = false;
    }
    if (s.crossDomain) {
        s.type = "GET";
    }
});

所以prefilters就是在特定的環境針對特定的情況做一些必要的兼容的處理

 


請求分發器 transports

請求分發器顧名思義發送請求,那么底層的ajax發送請求是通過send方法

xhr.send();

但是jQuery對send方法做了拆分,把對應的處理放到了transports中了

那么transports對象也是類似前置處理器通過jQuery.ajaxTransport構建

例如script,send,abort方法

返回出transports方法

transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);


免責聲明!

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



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