ajax源码解析-jQuery. ajaxPrefilter和jQuery. ajaxTransport

核心

jQuery. ajaxPrefilter前置处理器
jQuery. ajaxTransport请求分发器

流程图

参考

jQuery源码分析之ajaxTransport

源码注解

全局变量
var prefilter={};
jQuery.extend({
ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
ajaxTransport: addToPrefiltersOrTransports(transports),
})
<!--ajaxPrefilter和ajaxTransport的构造器-->
function addToPrefiltersOrTransports(structure) {
// dataTypeExpression is optional and defaults to "*"
<!--返回的是一个函数 此处应用的就是闭包-->
return function (dataTypeExpression, func) {
if (typeof dataTypeExpression !== "string") {
func = dataTypeExpression;
dataTypeExpression = "*";
}
if (jQuery.isFunction(func)) {
var dataTypes = dataTypeExpression.toLowerCase().split(rspacesAjax),
i = 0,
length = dataTypes.length,
dataType,
list,
placeBefore;
// For each dataType in the dataTypeExpression
for (; i < length; i++) {
dataType = dataTypes[i];
// We control if we're asked to add before
// any existing element
placeBefore = /^\+/.test(dataType);
if (placeBefore) {
dataType = dataType.substr(1) || "*";
}
list = structure[dataType] = structure[dataType] || [];
// then we add to the structure accordingly
list[placeBefore ? "unshift" : "push"](func);
}
}
};
}
jQuery.ajaxPrefilter("script", function (s) {
if (s.cache === undefined) {
s.cache = false;
}
if (s.crossDomain) {
s.type = "GET";
s.global = false;
}
});
jQuery.ajaxPrefilter("json jsonp", function (s, originalSettings, jqXHR) {
var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
( typeof s.data === "string" );
if (s.dataTypes[0] === "jsonp" ||
s.jsonp !== false && ( jsre.test(s.url) ||
inspectData && jsre.test(s.data) )) {
var responseContainer,
jsonpCallback = s.jsonpCallback =
jQuery.isFunction(s.jsonpCallback) ? s.jsonpCallback() : s.jsonpCallback,
previous = window[jsonpCallback],
url = s.url,
data = s.data,
replace = "$1" + jsonpCallback + "$2";
if (s.jsonp !== false) {
url = url.replace(jsre, replace);
if (s.url === url) {
if (inspectData) {
data = data.replace(jsre, replace);
}
if (s.data === data) {
// Add callback manually
url += (/\?/.test(url) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
}
}
}
s.url = url;
s.data = data;
// Install callback
window[jsonpCallback] = function (response) {
responseContainer = [response];
};
// Clean-up function
jqXHR.always(function () {
// Set callback back to previous value
window[jsonpCallback] = previous;
// Call if it was a function and we have a response
if (responseContainer && jQuery.isFunction(previous)) {
window[jsonpCallback](responseContainer[0]);
}
});
// Use data converter to retrieve json after script execution
s.converters["script json"] = function () {
if (!responseContainer) {
jQuery.error(jsonpCallback + " was not called");
}
return responseContainer[0];
};
// force json dataType
s.dataTypes[0] = "json";
// Delegate to script
return "script";
}
});
<!--处理跨域情况的-->
jQuery.ajaxTransport("script", function (s) {
// This transport only deals with cross domain requests
if (s.crossDomain) {
var script,
head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
return {
send: function (_, callback) {
script = document.createElement("script");
script.async = "async";
if (s.scriptCharset) {
script.charset = s.scriptCharset;
}
script.src = s.url;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function (_, isAbort) {
if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
// Remove the script
if (head && script.parentNode) {
head.removeChild(script);
}
// Dereference the script
script = undefined;
// Callback if not abort
if (!isAbort) {
callback(200, "success");
}
}
};
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore(script, head.firstChild);
},
abort: function () {
if (script) {
script.onload(0, 1);
}
}
};
}
});
<!--处理xmlHttpRequest请求-->
if (jQuery.support.ajax) {
jQuery.ajaxTransport(function (s) {
// Cross domain only allowed if supported through XMLHttpRequest
if (!s.crossDomain || jQuery.support.cors) {
var callback;
return {
send: function (headers, complete) {
// Get a new xhr
var xhr = s.xhr(),
handle,
i;
// Open the socket
// Passing null username, generates a login popup on Opera (#2865)
if (s.username) {
xhr.open(s.type, s.url, s.async, s.username, s.password);
} else {
xhr.open(s.type, s.url, s.async);
}
// Apply custom fields if provided
if (s.xhrFields) {
for (i in s.xhrFields) {
xhr[i] = s.xhrFields[i];
}
}
// Override mime type if needed
if (s.mimeType && xhr.overrideMimeType) {
xhr.overrideMimeType(s.mimeType);
}
// X-Requested-With header
// For cross-domain requests, seeing as conditions for a preflight are
// akin to a jigsaw puzzle, we simply never set it to be sure.
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
if (!s.crossDomain && !headers["X-Requested-With"]) {
headers["X-Requested-With"] = "XMLHttpRequest";
}
// Need an extra try/catch for cross domain requests in Firefox 3
try {
for (i in headers) {
xhr.setRequestHeader(i, headers[i]);
}
} catch (_) {
}
// Do send the request
// This may raise an exception which is actually
// handled in jQuery.ajax (so no try/catch here)
xhr.send(( s.hasContent && s.data ) || null);
// Listener
callback = function (_, isAbort) {
var status,
statusText,
responseHeaders,
responses,
xml;
// Firefox throws exceptions when accessing properties
// of an xhr when a network error occured
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
try {
// Was never called and is aborted or complete
if (callback && ( isAbort || xhr.readyState === 4 )) {
// Only called once
callback = undefined;
// Do not keep as active anymore
if (handle) {
xhr.onreadystatechange = jQuery.noop;
if (xhrOnUnloadAbort) {
delete xhrCallbacks[handle];
}
}
// If it's an abort
if (isAbort) {
// Abort it manually if needed
if (xhr.readyState !== 4) {
xhr.abort();
}
} else {
status = xhr.status;
responseHeaders = xhr.getAllResponseHeaders();
responses = {};
xml = xhr.responseXML;
// Construct response list
if (xml && xml.documentElement /* #4958 */) {
responses.xml = xml;
}
responses.text = xhr.responseText;
// Firefox throws an exception when accessing
// statusText for faulty cross-domain requests
try {
statusText = xhr.statusText;
} catch (e) {
// We normalize with Webkit giving an empty statusText
statusText = "";
}
// Filter status for non standard behaviors
// If the request is local and we have data: assume a success
// (success with no data won't get notified, that's the best we
// can do given current implementations)
if (!status && s.isLocal && !s.crossDomain) {
status = responses.text ? 200 : 404;
// IE - #1450: sometimes returns 1223 when it should be 204
} else if (status === 1223) {
status = 204;
}
}
}
} catch (firefoxAccessException) {
if (!isAbort) {
complete(-1, firefoxAccessException);
}
}
// Call complete if needed
if (responses) {
complete(status, statusText, responses, responseHeaders);
}
};
// if we're in sync mode or it's in cache
// and has been retrieved directly (IE6 & IE7)
// we need to manually fire the callback
if (!s.async || xhr.readyState === 4) {
callback();
} else {
handle = ++xhrId;
if (xhrOnUnloadAbort) {
// Create the active xhrs callbacks list if needed
// and attach the unload handler
if (!xhrCallbacks) {
xhrCallbacks = {};
jQuery(window).unload(xhrOnUnloadAbort);
}
// Add to list of active xhrs callbacks
xhrCallbacks[handle] = callback;
}
xhr.onreadystatechange = callback;
}
},
abort: function () {
if (callback) {
callback(0, 1);
}
}
};
}
});
}
sunbaixin wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!