上回说完request部分,这次就是response部分了。闲话少叙,切入正题。
处理response数据,jQuery的方式主要是使用ajaxHandleResponse(类型适配)和ajaxConvert(类型转换)。
先看下注册处理函数的流程:
transport.send( requestHeaders, done );
send: function( headers, complete ) {
// Listener
callback = function( _, isAbort ) {
// Call complete if needed
if ( responses ) {
complete( status, statusText, responses, xhr.getAllResponseHeaders() );
}
};
if ( !options.async ) {
// if we're in sync mode we fire the callback
callback();
} else if ( xhr.readyState === 4 ) {
// (IE6 & IE7) if it's in cache and has been
// retrieved directly we need to fire the callback
setTimeout( callback );
} else {
// Add to the list of active xhr callbacks
xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
}
}
这是普通的transport对象进行监听readystatechange事件,处理回调的方式。
send: function( _, callback ) {
script = document.createElement("script");
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function( _, isAbort ) {
if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
// Callback if not abort
if ( !isAbort ) {
callback( 200, "success" );
}
}
};
head.insertBefore( script, head.firstChild );
}
这是跨域的transport对象进行监听script的onload或readystatechange事件,处理回调的方式。
上述两种方式使用的都是done函数来处理数据,所以ajax的response部分着重就在于done函数了,来看下done方法:
function done( status, nativeStatusText, responses, headers ) {
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;
//略...
// Get response data
if ( responses ) {
response = ajaxHandleResponses( s, jqXHR, responses );
}
// Convert no matter what (that way responseXXX fields are always set)
response = ajaxConvert( s, response, jqXHR, isSuccess );
//略...
}
done函数处理response数据使用了ajaxHandleResponse和ajaxConvert。
类型适配主要做的是试着猜测对应的数据类型和返回改类型的数据,并且改变dataTypes的值。来看下类型适配:
send: function( headers, complete ) {
// Listener
callback = function( _, isAbort ) {
// Call complete if needed
if ( responses ) {
complete( status, statusText, responses, xhr.getAllResponseHeaders() );
}
};
if ( !options.async ) {
// if we're in sync mode we fire the callback
callback();
} else if ( xhr.readyState === 4 ) {
// (IE6 & IE7) if it's in cache and has been
// retrieved directly we need to fire the callback
setTimeout( callback );
} else {
// Add to the list of active xhr callbacks
xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
}
}
send: function( _, callback ) {
script = document.createElement("script");
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function( _, isAbort ) {
if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
// Callback if not abort
if ( !isAbort ) {
callback( 200, "success" );
}
}
};
head.insertBefore( script, head.firstChild );
}
function done( status, nativeStatusText, responses, headers ) {
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;
//略...
// Get response data
if ( responses ) {
response = ajaxHandleResponses( s, jqXHR, responses );
}
// Convert no matter what (that way responseXXX fields are always set)
response = ajaxConvert( s, response, jqXHR, isSuccess );
//略...
}
/* Handles responses to an ajax request:
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
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 ) {
//试着根据mimeType类型和头信息的Content-Type去猜测他的数据类型
ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
}
}
// Check if we're dealing with a known content-type
if ( ct ) {
for ( type in contents ) {
/*
xml: /xml/,
html: /html/,
json: /json/
符合上述三种类型会放到dataTypes中
*/
if ( contents[ type ] && contents[ type ].test( ct ) ) {
dataTypes.unshift( type );
break;
}
}
}
// Check to see if we have a response for the expected dataType
if ( dataTypes[ 0 ] in responses ) {
finalDataType = dataTypes[ 0 ];
} else {
// Try convertible dataTypes
for ( type in responses ) {
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {