6-12 类型的适配
本节编程练习不计算学习进度,请电脑登录imooc.com操作

类型的适配

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 函数需要在分发器中脚本加载后才能执行,从而才能截取到服务器返回的数据。

任务

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
  5. <title>类型的适配</title>
  6. <script src="http://code.jquery.com/jquery-latest.js"></script>
  7. </head>
  8. <body>
  9.  
  10.  
  11. <button id="test1">json类型</button>
  12. <button id="test2">xml类型</button>
  13. <ul></ul>
  14. <script type="text/javascript">
  15.  
  16. //执行一个异步的HTTP(Ajax)的请求。
  17. var ajax = $.ajax({
  18. crossDomain :true,
  19. url: 'http://192.168.1.113:8080/github/jQuery/jsonp.php',
  20. data: {
  21. 'action': 'aaron'
  22. },
  23. dataType: 'xml', // 数据类型
  24. jsonp: 'callback', // 指定回调函数名,与服务器端接收的一致,并回传回来
  25. //请求发送前的回调函数,用来修改请求发送前jqXHR
  26. beforeSend: function(xhr) {
  27. xhr.overrideMimeType("text/plain; charset=x-user-defined");
  28. console.log('局部事件beforeSend')
  29. },
  30. //请求完成后回调函数 (请求success 和 error之后均调用)
  31. complete: function() {
  32. console.log('局部事件complete')
  33. },
  34. error: function() {
  35. console.log('局部事件error请求失败时调用此函数')
  36. },
  37. success: function(data) {
  38. console.log('局部事件success',data)
  39. }
  40. })
  41.  
  42. ///////////////////////////////////////////////////
  43. // 有效的数据类型是text, html, xml, json,jsonp,和 script. //
  44. // 如果指定的是text 或 html, 则不会预处理。
  45. // 这些数据被简单地传递给成功处理函数,
  46. // 并通过该jqXHR对象的responseText属性获得的。
  47. ///////////////////////////////////////////////////
  48.  
  49.  
  50. /**
  51. * 服务端返回的一段文本
  52. * @type {String}
  53. */
  54. var data = '{"status":1,"info":"OK"}';
  55. /**
  56. * 服务器返回的xml
  57. * @type {String}
  58. */
  59. var xml = "<root><people><name>慕课网</name><address>北京</address></people></root>";
  60.  
  61. //////////////////////
  62. //dataType 为json的时候 //
  63. //converters =>text json
  64. //////////////////////
  65. function ajaxConvertJSON(data) {
  66. //内部转化成json的对象
  67. var parseJSON = function(data) {
  68. return JSON.parse(data + "");
  69. };
  70. return parseJSON(data)
  71. }
  72.  
  73. //////////////////////
  74. //dataType 为xml的时候 //
  75. //converters =>text xml
  76. //////////////////////
  77. function ajaxConvertXML(data) {
  78. var xml, tmp;
  79. try {
  80. tmp = new DOMParser();
  81. xml = tmp.parseFromString(data, "text/xml");
  82. } catch (e) {
  83. xml = undefined;
  84. }
  85. if (!xml || xml.getElementsByTagName("parsererror").length) {
  86. jQuery.error("Invalid XML: " + data);
  87. }
  88. return xml;
  89. }
  90.  
  91.  
  92. var $ul = $('ul')
  93.  
  94. function show(data) {
  95. $ul.append('<li>' + data + '</li>');
  96. }
  97.  
  98. $("#test1").click(function(){
  99. show(ajaxConvertJSON(data))
  100. })
  101.  
  102. $("#test2").click(function(){
  103. show(ajaxConvertXML(xml))
  104. })
  105.  
  106.  
  107.  
  108. </script>
  109. </body>
  110. </html>
下一节