Rewrote the data conversion logic in ajax. Should be cleaner and faster.

This commit is contained in:
jaubourg 2010-12-21 16:58:52 +01:00 committed by unknown
parent 0daf7223d0
commit 38101be048
2 changed files with 75 additions and 117 deletions

View file

@ -181,12 +181,7 @@ jQuery.extend({
xhr: function() { xhr: function() {
return new window.XMLHttpRequest(); return new window.XMLHttpRequest();
}, },
xhrResponseFields: {
xml: "XML",
text: "Text",
json: "JSON"
},
accepts: { accepts: {
xml: "application/xml, text/xml", xml: "application/xml, text/xml",
html: "text/html", html: "text/html",
@ -194,13 +189,13 @@ jQuery.extend({
json: "application/json, text/javascript", json: "application/json, text/javascript",
"*": "*/*" "*": "*/*"
}, },
autoDataType: { autoDataType: {
xml: /xml/, xml: /xml/,
html: /html/, html: /html/,
json: /json/ json: /json/
}, },
// Prefilters // Prefilters
// 1) They are useful to introduce custom dataTypes (see transport/jsonp for an example) // 1) They are useful to introduce custom dataTypes (see transport/jsonp for an example)
// 2) These are called: // 2) These are called:
@ -210,26 +205,26 @@ jQuery.extend({
// 4) the catchall symbol "*" can be used // 4) the catchall symbol "*" can be used
// 5) execution will start with transport dataType and THEN continue down to "*" if needed // 5) execution will start with transport dataType and THEN continue down to "*" if needed
prefilters: {}, prefilters: {},
// Transports bindings // Transports bindings
// 1) key is the dataType // 1) key is the dataType
// 2) the catchall symbol "*" can be used // 2) the catchall symbol "*" can be used
// 3) selection will start with transport dataType and THEN go to "*" if needed // 3) selection will start with transport dataType and THEN go to "*" if needed
transports: {}, transports: {},
// Checkers // Checkers
// 1) key is dataType // 1) key is dataType
// 2) they are called to control successful response // 2) they are called to control successful response
// 3) error throws is used as error data // 3) error throws is used as error data
dataCheckers: { dataCheckers: {
// Check if data is a string // Check if data is a string
"text": function(data) { "text": function(data) {
if ( typeof data != "string" ) { if ( typeof data != "string" ) {
jQuery.error("typeerror"); jQuery.error("typeerror");
} }
}, },
// Check if xml has been properly parsed // Check if xml has been properly parsed
"xml": function(data) { "xml": function(data) {
var documentElement = data ? data.documentElement : data; var documentElement = data ? data.documentElement : data;
@ -241,25 +236,25 @@ jQuery.extend({
} }
} }
}, },
// List of data converters // List of data converters
// 1) key format is "source_type => destination_type" (spaces required) // 1) key format is "source_type => destination_type" (spaces required)
// 2) the catchall symbol "*" can be used for source_type // 2) the catchall symbol "*" can be used for source_type
dataConverters: { dataConverters: {
// Convert anything to text // Convert anything to text
"* => text": function(data) { "* => text": function(data) {
return "" + data; return "" + data;
}, },
// Text to html (no transformation) // Text to html (no transformation)
"text => html": function(data) { "text => html": function(data) {
return data; return data;
}, },
// Evaluate text as a json expression // Evaluate text as a json expression
"text => json": jQuery.parseJSON, "text => json": jQuery.parseJSON,
// Parse text as xml // Parse text as xml
"text => xml": function(data) { "text => xml": function(data) {
var xml, parser; var xml, parser;

View file

@ -7,9 +7,7 @@ var rquery_xhr = /\?/,
rts = /([?&])_=[^&]*/, rts = /([?&])_=[^&]*/,
rurl = /^(\w+:)?\/\/([^\/?#]+)/, rurl = /^(\w+:)?\/\/([^\/?#]+)/,
sliceFunc = Array.prototype.slice, sliceFunc = Array.prototype.slice;
isFunction = jQuery.isFunction;
// Creates a jQuery xhr object // Creates a jQuery xhr object
jQuery.xhr = function( _native ) { jQuery.xhr = function( _native ) {
@ -147,7 +145,7 @@ jQuery.xhr = function( _native ) {
requestHeaders[ i.toLowerCase() ] = headers[ i ]; requestHeaders[ i.toLowerCase() ] = headers[ i ];
} }
} }
callbackContext = s.context || s; callbackContext = s.context || s;
globalEventContext = s.context ? jQuery(s.context) : jQuery.event; globalEventContext = s.context ? jQuery(s.context) : jQuery.event;
@ -224,111 +222,76 @@ jQuery.xhr = function( _native ) {
// (if an exception is thrown in the process, it'll be notified as an error) // (if an exception is thrown in the process, it'll be notified as an error)
try { try {
function checkData(data) { var i,
if ( data !== undefined ) { current,
var testFunction = s.dataCheckers[srcDataType]; prev,
if ( isFunction( testFunction ) ) { checker,
testFunction(data); conv1,
} conv2,
} oneConv,
} convertion,
dataTypes = s.dataTypes,
function convertData (data) { dataCheckers = s.dataCheckers,
var conversionFunction = dataConverters[srcDataType+" => "+destDataType] ||
dataConverters["* => "+destDataType],
noFunction = ! isFunction( conversionFunction );
if ( noFunction ) {
if ( srcDataType != "text" && destDataType != "text" ) {
// We try to put text inbetween
var first = dataConverters[srcDataType+" => text"] ||
dataConverters["* => text"],
second = dataConverters["text => "+destDataType] ||
dataConverters["* => "+destDataType],
areFunctions = isFunction( first ) && isFunction( second );
if ( areFunctions ) {
conversionFunction = function (data) {
return second( first ( data ) );
};
}
noFunction = ! areFunctions;
}
if ( noFunction ) {
jQuery.error( "no data converter between " + srcDataType + " and " + destDataType );
}
}
return conversionFunction(data);
}
var dataTypes = s.dataTypes,
i,
length,
data = response,
dataConverters = s.dataConverters, dataConverters = s.dataConverters,
srcDataType, dataFilter = s.dataFilter,
destDataType, responses = {
responseTypes = s.xhrResponseFields; "xml": "XML",
"text": "Text"
};
for( i = 0 ; i < dataTypes.length ; i++ ) {
for ( i = 0, length = dataTypes.length ; i < length ; i++ ) { current = dataTypes[ i ];
destDataType = dataTypes[i];
if ( !srcDataType ) { // First time if ( i ) {
// Copy type prev = dataTypes[ i - 1 ];
srcDataType = destDataType;
// Check if ( prev === "*" ) {
checkData(data);
// Apply dataFilter prev = current;
if ( isFunction( s.dataFilter ) ) {
data = s.dataFilter(data, s.dataType); } else if ( current !== "*" && prev !== current ) {
// Recheck data
checkData(data); oneConv = conv1 =
dataConverters[ ( conversion = prev + " => " + current ) ] ||
dataConverters[ "* => " + current ];
if ( ! oneConv && prev !== "text" && current !== "text" ) {
conv1 = dataConverters[ prev + " => text" ] || dataConverters[ "* => text" ];
conv2 = dataConverters[ "text => " + current ];
}
if ( oneConv || conv1 && conv2 ) {
response = oneConv ? conv1( response ) : conv2( conv1( response ) );
} else {
throw "no " + conversion;
}
} }
} else { // Subsequent times
// handle auto
// JULIAN: for reasons unknown to me === doesn't work here
if (destDataType == "*") {
destDataType = srcDataType;
} else if ( srcDataType != destDataType ) {
// Convert
data = convertData(data);
// Copy type & check
srcDataType = destDataType;
checkData(data);
}
}
// Copy response into the xhr if it hasn't been already
var responseDataType,
responseType = responseTypes[srcDataType];
if ( responseType ) {
responseDataType = srcDataType;
} else {
responseType = responseTypes[ responseDataType = "text" ];
}
if ( responseType !== 1 ) {
xhr[ "response" + responseType ] = data;
responseTypes[ responseType ] = 1;
} }
checker = dataCheckers[ current ];
if ( response != null && checker ) {
checker( response );
}
if ( responses[ current ] ) {
xhr[ "response" + responses[ current ] ] = response;
responses[ current ] = 0;
}
if ( ! i && dataFilter ) {
response = dataFilter( response );
dataTypes = s.dataTypes;
dataFilter = 0;
i--;
}
} }
// We have a real success // We have a real success
success = data; success = response;
isSuccess = 1; isSuccess = 1;
} catch(e) { } catch(e) {
@ -406,7 +369,7 @@ jQuery.xhr = function( _native ) {
// Ready state change // Ready state change
function setState( value ) { function setState( value ) {
xhr.readyState = value; xhr.readyState = value;
if ( isFunction( xhr.onreadystatechange ) ) { if ( jQuery.isFunction( xhr.onreadystatechange ) ) {
xhr.onreadystatechange(); xhr.onreadystatechange();
} }
} }