dataType 类型的转化
dataType 类型的参数,可以是 xml, json, script, or html 或者干脆为空,那么 jQuery 就需要一个方法去判断当前是属于什么数据处理,就此引入了 ajaxConvert 处理响应转化器,解析出正确的 dataType 类。
response = ajaxConvert(s, response, jqXHR, isSuccess);
分析下 dataType 无法就那么几种情况
1. dataType 为空,自动转化
此时 jQuery 只能根据头部信息来猜测当前需要处理的类型,删除掉通配 dataType,得到返回的 Content-Type。
while (dataTypes[0] === "*") {
dataTypes.shift();
if (ct === undefined) {
ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
}
}
通过 xhr.getAllResponseHeaders() 得到头部信息,然后去匹配 Content-Type 所有对象的值即可,当然找到这个 Content-Type = “html”,我们还得看看有没有对应处理的方法,如果有就需要替换这个 dataTypes。
看看是不是我们能处理的 Content-Type,比如图片这类二进制类型就不好处理了。
if (ct) {
// 实际上能处理的就是text、xml和json
for (type in contents) {
if (contents[type] && contents[type].test(ct)) {
dataTypes.unshift(type);
break;
}
}
}
经过这个流程后,dataTypes 本来是 * 就变成了对应的 html了,这是 jquery 内部的自动转化过。
2. dataType开发者指定
xml, json, script, html, jsop类型转换器将服务端响应的 responseText 或 responseXML,转换为请求时指定的数据类型 dataType,如果没有指定类型就依据响应头 Content-Type 自动处理。
类型转换器的执行过程
response = ajaxConvert(s, response, jqXHR, isSuccess);
流程
1.遍历dataTypes中对应的处理规则【"script","json"】
2.制作jqXHR对象的返回数据接口
json: "responseJSON"
text: "responseText"
xml: "responseXML"
如:jqXHR.responseText: "{"a":1,"b":2,"c":3,"d":4,"e":5}"
3.生成转化器对应的匹配规则,寻找合适的处理器
4.返回处理后的数据response
分析一下特殊的 jsonp 的转化流程,先看看转化对应的处理器。
jsonp
converters["script json"] = function() {
if (!responseContainer) {
jQuery.error(callbackName + " was not called");
}
return responseContainer[0];
};
jsonp 的转化器只是很简单的从 responseContainer 取出了对应的值,所以 responseContainer 肯定在转化之后就应该把数据给转化成数组对象了,当然做源码分析需要一点自己猜想能力,比如 responseContainer 这个数组对象如何而来?
那么我们知道 jsonp 的处理的原理,还是通过加载 script,然后服务器返回一个回调函数,responseContainer 数据就是回调函数的实参,所以需要满足 responseContainer 的处理,必须要先满足脚本先加载,所以我们要去分发器中找对应的加载代码,首先responseContainer 是内部变量,只有一个来源处,在预处理的时候增加一个全局的临时函数,然后代码肯定是执行了这个函数才能把 arguments 参数赋给 responseContainer。
overwritten = window[callbackName];
window[callbackName] = function() {
responseContainer = arguments;
};
//callbcakName是内部创建的一个尼玛函数名
jQuery203029543792246840894_1403062512436 = function() {
responseContainer = arguments;
};
我们发送请求:
http://192.168.1.114/yii/demos/test.php?backfunc=jQuery203029543792246840894_1403062512436&action=aaron&_=1403062601515
服务器那边就回调后,执行了 jQuery203029543792246840894_1403062512436(responseContainer ) 所以全局的 callbackName 函数需要在分发器中脚本加载后才能执行,从而才能截取到服务器返回的数据。
<!doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <title>类型的适配</title> <script src="http://code.jquery.com/jquery-latest.js"></script> </head> <body> <button id="test1">json类型</button> <button id="test2">xml类型</button> <ul></ul> <script type="text/javascript"> //执行一个异步的HTTP(Ajax)的请求。 var ajax = $.ajax({ crossDomain :true, url: 'http://192.168.1.113:8080/github/jQuery/jsonp.php', data: { 'action': 'aaron' }, dataType: 'xml', // 数据类型 jsonp: 'callback', // 指定回调函数名,与服务器端接收的一致,并回传回来 //请求发送前的回调函数,用来修改请求发送前jqXHR beforeSend: function(xhr) { xhr.overrideMimeType("text/plain; charset=x-user-defined"); console.log('局部事件beforeSend') }, //请求完成后回调函数 (请求success 和 error之后均调用) complete: function() { console.log('局部事件complete') }, error: function() { console.log('局部事件error请求失败时调用此函数') }, success: function(data) { console.log('局部事件success',data) } }) /////////////////////////////////////////////////// // 有效的数据类型是text, html, xml, json,jsonp,和 script. // // 如果指定的是text 或 html, 则不会预处理。 // 这些数据被简单地传递给成功处理函数, // 并通过该jqXHR对象的responseText属性获得的。 /////////////////////////////////////////////////// /** * 服务端返回的一段文本 * @type {String} */ var data = '{"status":1,"info":"OK"}'; /** * 服务器返回的xml * @type {String} */ var xml = "<root><people><name>慕课网</name><address>北京</address></people></root>"; ////////////////////// //dataType 为json的时候 // //converters =>text json ////////////////////// function ajaxConvertJSON(data) { //内部转化成json的对象 var parseJSON = function(data) { return JSON.parse(data + ""); }; return parseJSON(data) } ////////////////////// //dataType 为xml的时候 // //converters =>text xml ////////////////////// function ajaxConvertXML(data) { var xml, tmp; try { tmp = new DOMParser(); xml = tmp.parseFromString(data, "text/xml"); } catch (e) { xml = undefined; } if (!xml || xml.getElementsByTagName("parsererror").length) { jQuery.error("Invalid XML: " + data); } return xml; } var $ul = $('ul') function show(data) { $ul.append('<li>' + data + '</li>'); } $("#test1").click(function(){ show(ajaxConvertJSON(data)) }) $("#test2").click(function(){ show(ajaxConvertXML(xml)) }) </script> </body> </html>