上一篇文章 ,將jQuery.ajax中的一些細節補充完。這篇文章講解如果將類AJAX方法都包裝進jQuery.ajax中。下篇文章則講解各預過濾器和分發器的細節。
?
為什么要包裝起來??
我們知道,古老的XMLHttpRequest出于同源策略考慮,是不支持跨域的。所以,在前端想動態加載跨域Javascript腳本,通常是使用被稱為Script DOM Element的方案,如:
var
scriptElem = document.createElement("script"
);
scriptElem.src
= "http://anydomain.com/A.js"
;
document.getElementsByTagName(
"head")[0].appendChild(scriptElem);
同理,JSON也無法通過XMLHttpRequest進行跨域,所以利用Script DOM Element,將JSON填入一個回調函數中來實現其跨域,也就是JSONP(JSON with padding, 填充式JSON或參數式JSON)。
實際上JSONP就是將,得到JSON后回調的函數通過GET傳參告訴服務器,然后服務器拼接一段腳本,用該回調函數并參數為需要的JSON數據,如:
callback({ "name": "Justany_WhiteSnow" });
jQuery團隊當然希望開發者開發的時候,不需要想需不需要跨域,只要直接使用就行了。
所以他們把XMLHttpRequest、Script DOM Element、JSONP包裝起來,都當成AJAX來使用。
這里順便提一下,其實現代瀏覽器(Firefox 3.5+、Safari 4+、Chrome等)中,通過XMLHttpRequeest實現了CORS(Cross-Origin Resource Sharing, 跨源資源共享)原生支持。也就是XMLHttpRequest在某些瀏覽器中,實際上是可以跨域的,只需要設置一下HTTP Response Header中的Access-Control-Allow-Origin。比如設置成通配符*。
而IE8也引入XDomainRequest也實現了CORS。
但畢竟某些瀏覽器不行,所以,咳咳……這不能成為一種通用方案。
?
怎么包裝起來??
首先我們有一個山寨XHR對象,也就是jqXHR對象。通過對其添加 send、 abort來模擬XHR對象。
可是我們需要在不同方案執行前先處理一下特異性的東東,所以我們需要一個預過濾機制( Prefilter )來預先處理一下。
然后我們需要知道到底應當用那一套方案來執行整個過程,所以我們需要一個分發機制( Transport )來得到最后的jqXHR對象。
?
inspectPrefiltersOrTransports
我們在jQuery.ajax找到了預過濾和分發機制的函數,inspectPrefiltersOrTransports。
//
預過濾
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
//
……
//
得到transport
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
然后我們看看這個函數在干些什么。
//
檢測函數,預過濾或者分發器
function
inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
//
定義個參數對象
var
inspected =
{},
//
看看傳進來的結構體是prefilters, 還是transports
//
如果是prefilters,證明這是預過濾過程,如果是transports分發過程
//
所以這個是,是不是在分發過程
seekingTransport = ( structure ===
transports );
function
inspect( dataType ) {
var
selected;
//
將inspected的dataType對應屬性設置成true
inspected[ dataType ] =
true
;
//
遍歷prefilters對應dataType對象中的所有過濾器或者轉換器工廠函數
jQuery.each( structure[ dataType ] || [],
function
( _, prefilterOrFactory ) {
//
得到dataType或者轉換器
var
dataTypeOrTransport =
prefilterOrFactory( options, originalOptions, jqXHR );
//
如果dataType為字符串,即上面過程是過濾器
//
如果在預過濾過程
//
并且這個過濾出來的dataType不等于剛開始傳進來的dataType
if
(
typeof
dataTypeOrTransport === "string" && !seekingTransport && !
inspected[ dataTypeOrTransport ] ) {
//
將現在這個新的dataType插入到options中
options.dataTypes.unshift( dataTypeOrTransport );
//
檢測新的dataType
inspect( dataTypeOrTransport );
return
false
;
//
否則如果在分發過程
}
else
if
( seekingTransport ) {
//
定義selected為dataTypeOrTransport
return
!( selected =
dataTypeOrTransport );
}
});
return
selected;
}
//
檢查dataTypes數組的第一個,如果結果是undefined,
//
則看看上面檢查的是不是通配符*,如果不是則檢查通配符
return
inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*"
);
}
我們可以看到,這個函數實際上就是從prefilters和transports中取出對應dataType的東東,然后過濾或者分發。
那么怎么定義prefilters和transports這兩個對象的呢?
?
jQuery.ajaxPrefilter & jQuery.ajaxTransport
實際上,jQuery是通過這兩個接口來定義上面兩個對象的內容的,一個是定義預過濾器,另一個則定義分發器。
jQuery.ajaxPrefilter =
addToPrefiltersOrTransports( prefilters );
jQuery.ajaxTransport
= addToPrefiltersOrTransports( transports );
而這兩個方法都是由addToPrefiltersOrTransports生成的。
?
addToPrefiltersOrTransports
//
jQuery.ajaxPrefilter和jQuery.ajaxTransport的構造函數
function
addToPrefiltersOrTransports( structure ) {
//
dataTypeExpression是可選參數,缺省值為*
return
function
( dataTypeExpression, func ) {
//
如果dataTypeExpression不是字符串
//
模擬重載
if
(
typeof
dataTypeExpression !== "string"
) {
func
=
dataTypeExpression;
//
缺省為*
dataTypeExpression = "*"
;
}
var
dataType,
i
= 0
,
//
將dataTypeExpression轉為小寫,并用空白拆成數組
dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) ||
[];
//
如果func是一個函數
if
( jQuery.isFunction( func ) ) {
//
遍歷dataTypeExpression中的所有dataType
while
( (dataType = dataTypes[i++
]) ) {
//
如果有必要則刪除頭部的+號
if
( dataType[0] === "+"
) {
//
刪除+號
dataType = dataType.slice( 1 ) || "*"
;
//
往structure對應的dataType中推入func函數
(structure[ dataType ] = structure[ dataType ] ||
[]).unshift( func );
//
否則不需要處理
}
else
{
//
往structure對應的dataType中推入func函數
(structure[ dataType ] = structure[ dataType ] ||
[]).push( func );
}
}
}
};
}
接下來就是通過調用jQuery.ajaxPrefilter和jQuery.ajaxTransport方法,添加預過濾器和分發器來完成包裝。
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

