ajax源码解析-jQuery. ajaxPrefilter和jQuery. ajaxTransport 发表于 2016-11-05 | 分类于 js | | 阅读次数: 字数统计: | 阅读时长 ≈ 核心 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); } } }; } }); } 欢迎您扫一扫上面的微信公众号,订阅我的博客!