(function( jQuery ) {
-var // Next fake timer id
- xhrPollingId = jQuery.now(),
+var // Next active xhr id
+ xhrId = jQuery.now(),
- // Callbacks hashtable
+ // active xhrs
xhrs = {},
- // #5280: see end of file
- xhrUnloadAbortMarker = [];
+ // #5280: see below
+ xhrUnloadAbortInstalled;
jQuery.ajax.transport( function( s , determineDataType ) {
send: function(headers, complete) {
+ // #5280: we need to abort on unload or IE will keep connections alive
+ if ( ! xhrUnloadAbortInstalled ) {
+
+ xhrUnloadAbortInstalled = 1;
+
+ jQuery(window).bind( "unload" , function() {
+
+ // Abort all pending requests
+ jQuery.each(xhrs, function(_, xhr) {
+ if ( xhr.onreadystatechange ) {
+ xhr.onreadystatechange( 1 );
+ }
+ });
+
+ });
+ }
+
+ // Get a new xhr
var xhr = s.xhr(),
handle;
// Requested-With header
// Not set for crossDomain requests with no content
// (see why at http://trac.dojotoolkit.org/ticket/9486)
- // Won't change header if already provided in beforeSend
+ // Won't change header if already provided
if ( ! ( s.crossDomain && ! s.hasContent ) && ! headers["x-requested-with"] ) {
headers["x-requested-with"] = "XMLHttpRequest";
}
}
// Listener
- callback = function ( abortStatusText ) {
+ callback = function( _ , isAbort ) {
// Was never called and is aborted or complete
- if ( callback && ( abortStatusText || xhr.readyState === 4 ) ) {
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = 0;
- // Do not listen anymore
+ // Do not keep as active anymore
+ // and store back into pool
if (handle) {
xhr.onreadystatechange = jQuery.noop;
delete xhrs[ handle ];
- handle = undefined;
}
- callback = 0;
-
- // Get info
- var status, statusText, response, responseHeaders;
-
- if ( abortStatusText ) {
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
if ( xhr.readyState !== 4 ) {
xhr.abort();
}
-
- // Stop here if unloadAbort
- if ( abortStatusText === xhrUnloadAbortMarker ) {
- return;
- }
-
- status = 0;
- statusText = abortStatusText;
-
} else {
- status = xhr.status;
+ // Get info
+ var status = xhr.status,
+ statusText,
+ response,
+ responseHeaders = xhr.getAllResponseHeaders();
try { // Firefox throws an exception when accessing statusText for faulty cross-domain requests
}
- responseHeaders = xhr.getAllResponseHeaders();
-
// Filter status for non standard behaviours
// (so many they seem to be the actual "standard")
status =
status
);
- // Guess response if needed & update datatype accordingly
- if ( status >= 200 && status < 300 ) {
- response =
- determineDataType(
- s,
- xhr.getResponseHeader("content-type"),
- xhr.responseText,
- xhr.responseXML );
- }
- }
+ // Guess response & update dataType accordingly
+ response =
+ determineDataType(
+ s,
+ xhr.getResponseHeader("content-type"),
+ xhr.responseText,
+ xhr.responseXML );
- // Call complete
- complete(status,statusText,response,responseHeaders);
+ // Call complete
+ complete(status,statusText,response,responseHeaders);
+ }
}
};
} else {
- // Listener is externalized to handle abort on unload
- handle = xhrPollingId++;
+ // Add to list of active xhrs
+ handle = xhrId++;
xhrs[ handle ] = xhr;
- xhr.onreadystatechange = function() {
- callback();
- };
+ xhr.onreadystatechange = callback;
}
},
- abort: function(statusText) {
+ abort: function() {
if ( callback ) {
- callback(statusText);
+ callback(0,1);
}
}
};
}
});
-// #5280: we need to abort on unload or IE will keep connections alive
-jQuery(window).bind( "unload" , function() {
-
- // Abort all pending requests
- jQuery.each(xhrs, function(_, xhr) {
- if ( xhr.onreadystatechange ) {
- xhr.onreadystatechange( xhrUnloadAbortMarker );
- }
- });
-
- // Resest polling structure to be safe
- xhrs = {};
-
-});
-
})( jQuery );