ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加
然后php方就会执行backfunc(传递参数);
所以流程就会分二步:
1:针对jsonp的预处理,主要是转化拼接这些参数,然后处理缓存,因为jsonp的方式也是靠加载script所以要关闭浏览器缓存
inspectPrefiltersOrTransports中,当作了jsonp的预处理后,还要在执行inspect(dataTypeOrTransport);的递归,就是为了关闭这个缓存机制
var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR); /** * 针对jonsp处理 */ if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) { //增加cache设置标记 //不需要缓存 //dataTypes: Array[2] // 0: "script" // 1: "json" options.dataTypes.unshift(dataTypeOrTransport); inspect(dataTypeOrTransport); return false; } else if (seekingTransport) { return !(selected = dataTypeOrTransport); }
具体的预处理的代码
// Detect, normalize options and install callbacks for jsonp requests // 向前置过滤器对象中添加特定类型的过滤器 // 添加的过滤器将格式化参数,并且为jsonp请求增加callbacks jQuery.ajaxPrefilter("json jsonp", function(s, originalSettings, jqXHR) { var callbackName, overwritten, responseContainer, // 如果是表单提交,则需要检查数据 jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ? "url" : typeof s.data === "string" && !(s.contentType || "").indexOf("application/x-www-form-urlencoded") && rjsonp.test(s.data) && "data" ); // Handle iff the expected data type is "jsonp" or we have a parameter to set // 这个方法只处理jsonp,如果json的url或data有jsonp的特征,会被当成jsonp处理 if (jsonProp || s.dataTypes[0] === "jsonp") { // Get callback name, remembering preexisting value associated with it // s.jsonpCallback时函数,则执行函数用返回值做为回调函数名 callbackName = s.jsonpCallback = jQuery.isFunction(s.jsonpCallback) ? s.jsonpCallback() : s.jsonpCallback; // Insert callback into url or form data // 插入回调url或表单数据 // "test.php?symbol=IBM&callback=jQuery20309245402452070266_1402451299022" if (jsonProp) { s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName); } else if (s.jsonp !== false) { s.url += (ajax_rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName; } // Use data converter to retrieve json after script execution s.converters["script json"] = function() { if (!responseContainer) { jQuery.error(callbackName + " was not called"); } return responseContainer[0]; }; // force json dataType // 强制跟换类型 s.dataTypes[0] = "json"; // Install callback // 增加一个全局的临时函数 overwritten = window[callbackName]; window[callbackName] = function() { responseContainer = arguments; }; // Clean-up function (fires after converters) // 在代码执行完毕后清理这个全部函数 jqXHR.always(function() { // Restore preexisting value window[callbackName] = overwritten; // Save back as free if (s[callbackName]) { // make sure that re-using the options doesn't screw things around s.jsonpCallback = originalSettings.jsonpCallback; // save the callback name for future use oldCallbacks.push(callbackName); } // Call if it was a function and we have a response if (responseContainer && jQuery.isFunction(overwritten)) { overwritten(responseContainer[0]); } responseContainer = overwritten = undefined; }); // Delegate to script return "script"; } });
jquery会在window对象中加载一个全局的函数,当代码插入时函数执行,执行完毕后就会被移除。同时jquery还对非跨域的请求进行了优化,如果这个请求是在同一个域名下那么他就会像正常的Ajax请求一样工作。
分发器执行代码:
当我们所有的参数都转化好了,此时会经过请求发送器用来处理发送的具体
为什么会叫做分发器,因为发送的请求目标
ajax因为参杂了jsonp的处理,所以实际上的请求不是通过 xhr.send(XmlHttpRequest)发送的
而是通过get方式的脚本加载的
所以
transports对象在初始化构件的时候,会生成2个处理器
- *: Array[1] 针对xhr方式
- script: Array[1] 针对script,jsonp方式
所以
transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
那么得到的transport就会根据当前的处理的类型,来选择采用哪种发送器(*、script)
针对script的请求器
jQuery.ajaxTransport("script", function(s) { // This transport only deals with cross domain requests if (s.crossDomain) { var script, callback; return { send: function(_, complete) { script = jQuery("