From 1db2f02cc78b10bd638d70457645e1daa5c01344 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Tue, 21 Dec 2010 16:58:52 +0100 Subject: [PATCH] Rewrote the data conversion logic in ajax. Should be cleaner and faster. --- src/ajax.js | 29 +++++------- src/xhr.js | 151 ++++++++++++++++++++++------------------------------------- 2 files changed, 69 insertions(+), 111 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index 320c13d..a50a039 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -181,12 +181,7 @@ jQuery.extend({ xhr: function() { return new window.XMLHttpRequest(); }, - xhrResponseFields: { - xml: "XML", - text: "Text", - json: "JSON" - }, - + accepts: { xml: "application/xml, text/xml", html: "text/html", @@ -194,13 +189,13 @@ jQuery.extend({ json: "application/json, text/javascript", "*": "*/*" }, - + autoDataType: { xml: /xml/, html: /html/, json: /json/ }, - + // Prefilters // 1) They are useful to introduce custom dataTypes (see transport/jsonp for an example) // 2) These are called: @@ -210,26 +205,26 @@ jQuery.extend({ // 4) the catchall symbol "*" can be used // 5) execution will start with transport dataType and THEN continue down to "*" if needed prefilters: {}, - + // Transports bindings // 1) key is the dataType // 2) the catchall symbol "*" can be used // 3) selection will start with transport dataType and THEN go to "*" if needed transports: {}, - + // Checkers // 1) key is dataType // 2) they are called to control successful response // 3) error throws is used as error data dataCheckers: { - + // Check if data is a string "text": function(data) { if ( typeof data != "string" ) { jQuery.error("typeerror"); } }, - + // Check if xml has been properly parsed "xml": function(data) { var documentElement = data ? data.documentElement : data; @@ -241,25 +236,25 @@ jQuery.extend({ } } }, - + // List of data converters // 1) key format is "source_type => destination_type" (spaces required) // 2) the catchall symbol "*" can be used for source_type dataConverters: { - + // Convert anything to text "* => text": function(data) { return "" + data; }, - + // Text to html (no transformation) "text => html": function(data) { return data; }, - + // Evaluate text as a json expression "text => json": jQuery.parseJSON, - + // Parse text as xml "text => xml": function(data) { var xml, parser; diff --git a/src/xhr.js b/src/xhr.js index e792e1d..1993e0b 100644 --- a/src/xhr.js +++ b/src/xhr.js @@ -7,9 +7,7 @@ var rquery_xhr = /\?/, rts = /([?&])_=[^&]*/, rurl = /^(\w+:)?\/\/([^\/?#]+)/, - sliceFunc = Array.prototype.slice, - - isFunction = jQuery.isFunction; + sliceFunc = Array.prototype.slice; // Creates a jQuery xhr object jQuery.xhr = function( _native ) { @@ -86,7 +84,7 @@ jQuery.xhr = function( _native ) { if ( data && s.processData && typeof data != "string" ) { data = s.data = jQuery.param( data , s.traditional ); } - + // Get internal internal = jQuery.xhr.prefilter( s ).transport( s ); @@ -147,7 +145,7 @@ jQuery.xhr = function( _native ) { requestHeaders[ i.toLowerCase() ] = headers[ i ]; } } - + callbackContext = s.context || s; 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) try { - function checkData(data) { - if ( data !== undefined ) { - var testFunction = s.dataCheckers[srcDataType]; - if ( isFunction( testFunction ) ) { - testFunction(data); - } - } - } - - function convertData (data) { - 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, + var i, + current, + prev, + checker, + conv1, + conv2, + oneConv, + convertion, + dataTypes = s.dataTypes, + dataCheckers = s.dataCheckers, dataConverters = s.dataConverters, - srcDataType, - destDataType, - responseTypes = s.xhrResponseFields; + dataFilter = s.dataFilter, + responses = { + "xml": "XML", + "text": "Text" + }; + + for( i = 0 ; i < dataTypes.length ; i++ ) { - for ( i = 0, length = dataTypes.length ; i < length ; i++ ) { - - destDataType = dataTypes[i]; + current = dataTypes[ i ]; - if ( !srcDataType ) { // First time + if ( i ) { - // Copy type - srcDataType = destDataType; - // Check - checkData(data); - // Apply dataFilter - if ( isFunction( s.dataFilter ) ) { - data = s.dataFilter(data, s.dataType); - // Recheck data - checkData(data); - } - - } else { // Subsequent times + prev = dataTypes[ i - 1 ]; - // handle auto - // JULIAN: for reasons unknown to me === doesn't work here - if (destDataType == "*") { - - destDataType = srcDataType; + if ( prev === "*" ) { - } else if ( srcDataType != destDataType ) { + prev = current; - // Convert - data = convertData(data); - // Copy type & check - srcDataType = destDataType; - checkData(data); + } else if ( current !== "*" && prev !== current ) { + + 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; + } } - } - - // 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" ]; - + checker = dataCheckers[ current ]; + + if ( response != null && checker ) { + checker( response ); } - - if ( responseType !== 1 ) { - xhr[ "response" + responseType ] = data; - responseTypes[ responseType ] = 1; + + 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 - success = data; + success = response; isSuccess = 1; } catch(e) { @@ -406,7 +369,7 @@ jQuery.xhr = function( _native ) { // Ready state change function setState( value ) { xhr.readyState = value; - if ( isFunction( xhr.onreadystatechange ) ) { + if ( jQuery.isFunction( xhr.onreadystatechange ) ) { xhr.onreadystatechange(); } } -- 1.7.10.4