var xhr=new XMLHttpRequest();xhr.onreadystatechange=function(e){ console.log(e); if(xhr.readyState==4 && xhr.status==200){ console.log(xhr); console.log(xhr.responseText); }}xhr.open('get','./data.json');xhr.send();
response中已经有了数据,响应内容默认为字符串
responseType为'',也就是默认值
responseText中是响应主体的内容
responseURL指出了咱们请求的资源路径javascript
上图中的信息:responseType是一个空字符串,也就是指明了返回的是一个字符串,并且从下面的log咱们也能够看出来,为了清楚,我把xhr.responseText的类型也打印了出来,确实是string。
而若是咱们换成下面的代码:html
var xhr=$.ajax({ url:'./data.json', success:function(data){ console.log(data); } }); console.log(xhr);
获得结果截图以下:
这个被jQuery改的面目全非的xmlhttprequest对象,先看一个左侧的属性,其中有一个responseJSON,这是jquery的实现,标准中是没有这个属性的,而它的responseText是字符串。因此success回调应该就是调的这个属性咯。看下请求,没有什么区别:Content-Type都是application/json ,其实咱们再切到response标签看下,是同样的数据格式。因此是否是能够说原生获取json格式数据的话,值都是json字符串形式的值?前端
这里的jquery版本为1.11.2,查看源码能够发现:在ajax方法中定义的done方法内,有这么一句:java
// Get response data 这里是获得相应的内容,本例就是"'{"username":"ruby","age":"18"}'"if ( responses ) { response = ajaxHandleResponses( s, jqXHR, responses );}// Convert no matter what (that way responseXXX fields are always set)response = ajaxConvert( s, response, jqXHR, isSuccess );
也就是说,在获得最终请求数据时,jquery会去作响应内容的自动转换,先来看ajaxHandleResponses方法,它用于返回响应内容:jquery
function ajaxHandleResponses(s, jqXHR, responses) { var firstDataType, ct, finalDataType, type, contents = s.contents, dataTypes = s.dataTypes; // Remove auto dataType and get content-type in the process while (dataTypes[0] === "*") { dataTypes.shift(); if (ct === undefined) { ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); /*这里的s是使用ajax传入的参数转化而来的对象,用于存储前端开发人员发起该请求时对请求的一些设置和js默认对请求的设置,s.mimeType是使用overrideMIMEType时会被写入s的,其实也就是在ajax方法中咱们指定的contentType,若是没有该属性,就是查找相应对象的Content-Type属性,而这个是确定有值的,本例中ct='application/json',即获取到了响应报文中报头Content-Type的值*/ } } // Check if we're dealing with a known content-type if (ct) { for (type in contents) { /* contents是一个固定的对象,用于匹配各类类型的数据 { html: /html/ json: /json/ script: /(?:java|ecma)script/ xml: /xml/ } */ if (contents[type] && contents[type].test(ct)) { dataTypes.unshift(type); /* 这里咱们显然是匹配到了json这一项,因此dataTypes中加上一项['json'] */ break; } } } // Check to see if we have a response for the expected dataType if (dataTypes[0] in responses) { finalDataType = dataTypes[0]; /* 若是这个类型的数据在responses中正好有,那么就直接将最终类型定义为dataType中的这一项,本例中,dataTypes[0]为'json',但实际返回的响应是text。responses就是根据相应内容生成的响应对象,这里是"{text:"{"username":"ruby","age":"18"}"}". */ } else { // Try convertible dataTypes for (type in responses) { if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) { /* 检测responses中的各个类型的值是否能够转换为咱们想获得的类型, 本例中这里的type为'text',s.converters定义的是各类转换用到的函数,好比s.converters['text json']=JSON.parse。本例中这里是能够转换的。列出来吧: s.converters:{ "text script": function( text ) { jQuery.globalEval( text ); return text; }, // Convert anything to text "* text": String, // Text to html (true = no transformation) "text html": true, // Evaluate text as a json expression "text json": jQuery.parseJSON, // Parse text as xml "text xml": jQuery.parseXML } */ finalDataType = type; break; } if (!firstDataType) { firstDataType = type; } } // Or just use first one finalDataType = finalDataType || firstDataType; } // If we found a dataType // We add the dataType to the list if needed // and return the corresponding response if (finalDataType) { if (finalDataType !== dataTypes[0]) { dataTypes.unshift(finalDataType); //完善s.dataTypes中的值,即完善响应数据的类型,此时为['text','json'] } return responses[finalDataType]; //最终返回responses['text'] }}
再来看ajaxConvert方法: ajax
/* Chain conversions given the request and the original response* Also sets the responseXXX fields on the jqXHR instance*/function ajaxConvert(s, response, jqXHR, isSuccess) { var conv2, current, conv, tmp, prev, converters = {}, // Work with a copy of dataTypes in case we need to modify it for conversion dataTypes = s.dataTypes.slice(); //数组copy这么写?不知道为啥~你知道的话还望不吝赐教~ // Create converters map with lowercased keys if (dataTypes[1]) { for (conv in s.converters) { converters[conv.toLowerCase()] = s.converters[conv]; //构造一个转换对象,内容是s.converters中的那些转换函数. } } current = dataTypes.shift(); // Convert to each sequential dataType while (current) { if (s.responseFields[current]) { jqXHR[s.responseFields[current]] = response; /* 这里给jqXHR即jquery构造出来的XMLHttpRequest对象赋值,在本例中,它在此添加了两个属性,一个是responseText,一个是responseJson */ } // Apply the dataFilter if provided if (!prev && isSuccess && s.dataFilter) { response = s.dataFilter(response, s.dataType); } prev = current; current = dataTypes.shift(); //记住第一个类型,再获取第二个类型,这里的prev为‘text’, current为'json'。 if (current) { // There's only work to do if current dataType is non-auto if (current === "*") { current = prev; // Convert response if prev dataType is non-auto and differs from current } else if (prev !== "*" && prev !== current) { // Seek a direct converter conv = converters[prev + " " + current] || converters["* " + current]; //看看是否有prev类转current类的转换方法 // If none found, seek a pair if (!conv) { for (conv2 in converters) { // If conv2 outputs current tmp = conv2.split(" "); if (tmp[1] === current) { // If prev can be converted to accepted input conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]]; if (conv) { // Condense equivalence converters if (conv === true) { conv = converters[conv2]; // Otherwise, insert the intermediate dataType } else if (converters[conv2] !== true) { current = tmp[0]; dataTypes.unshift(tmp[1]); } break; } } } } // Apply converter (if not an equivalence) if (conv !== true) { // Unless errors are allowed to bubble, catch and return them if (conv && s["throws"]) { response = conv(response); } else { try { response = conv(response); //转换为咱们想要的数据类型,截至此咱们已经获得想要的json数据啦 } catch (e) { return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; } } } } } } return {state: "success", data: response};}
上面基本根据当前案例进行代码解析,不少状况没有一一列出,感兴趣的童鞋能够经过打断点调试的方式来解析代码。express