Skip to content

Commit 727f86c

Browse files
committed
2.0: reduced xhr transport
1 parent b0e40a4 commit 727f86c

File tree

2 files changed

+104
-228
lines changed

2 files changed

+104
-228
lines changed

src/ajax/xhr.js

Lines changed: 84 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -1,218 +1,92 @@
1-
var xhrCallbacks, xhrSupported,
2-
xhrId = 0,
3-
// #5280: Internet Explorer will keep connections alive if we don't abort on unload
4-
xhrOnUnloadAbort = window.ActiveXObject && function() {
5-
// Abort all pending requests
6-
var key;
7-
for ( key in xhrCallbacks ) {
8-
xhrCallbacks[ key ]( undefined, true );
9-
}
10-
};
11-
12-
// Functions to create xhrs
13-
function createStandardXHR() {
1+
jQuery.ajaxSettings.xhr = function() {
142
try {
15-
return new window.XMLHttpRequest();
3+
return new XMLHttpRequest();
164
} catch( e ) {}
17-
}
18-
19-
function createActiveXHR() {
20-
try {
21-
return new window.ActiveXObject("Microsoft.XMLHTTP");
22-
} catch( e ) {}
23-
}
24-
25-
// Create the request object
26-
// (This is still attached to ajaxSettings for backward compatibility)
27-
jQuery.ajaxSettings.xhr = window.ActiveXObject ?
28-
/* Microsoft failed to properly
29-
* implement the XMLHttpRequest in IE7 (can't request local files),
30-
* so we use the ActiveXObject when it is available
31-
* Additionally XMLHttpRequest can be disabled in IE7/IE8 so
32-
* we need a fallback.
33-
*/
34-
function() {
35-
return !this.isLocal && createStandardXHR() || createActiveXHR();
36-
} :
37-
// For all other browsers, use the standard XMLHttpRequest object
38-
createStandardXHR;
39-
40-
// Determine support properties
41-
xhrSupported = jQuery.ajaxSettings.xhr();
5+
};
6+
7+
var xhrSupported = jQuery.ajaxSettings.xhr(),
8+
xhrSuccessStatus = {
9+
// file protocol always yields status code 0, assume 200
10+
0: 200,
11+
// IE - #1450: sometimes returns 1223 when it should be 204
12+
1223: 204
13+
};
14+
4215
jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
43-
xhrSupported = jQuery.support.ajax = !!xhrSupported;
44-
45-
// Create transport if the browser can provide an xhr
46-
if ( xhrSupported ) {
47-
48-
jQuery.ajaxTransport(function( s ) {
49-
// Cross domain only allowed if supported through XMLHttpRequest
50-
if ( !s.crossDomain || jQuery.support.cors ) {
51-
52-
var callback;
53-
54-
return {
55-
send: function( headers, complete ) {
56-
57-
// Get a new xhr
58-
var handle, i,
59-
xhr = s.xhr();
60-
61-
// Open the socket
62-
// Passing null username, generates a login popup on Opera (#2865)
63-
if ( s.username ) {
64-
xhr.open( s.type, s.url, s.async, s.username, s.password );
65-
} else {
66-
xhr.open( s.type, s.url, s.async );
67-
}
68-
69-
// Apply custom fields if provided
70-
if ( s.xhrFields ) {
71-
for ( i in s.xhrFields ) {
72-
xhr[ i ] = s.xhrFields[ i ];
73-
}
74-
}
75-
76-
// Override mime type if needed
77-
if ( s.mimeType && xhr.overrideMimeType ) {
78-
xhr.overrideMimeType( s.mimeType );
16+
jQuery.support.ajax = xhrSupported = !!xhrSupported;
17+
18+
jQuery.ajaxTransport(function( options ) {
19+
var callback;
20+
// Cross domain only allowed if supported through XMLHttpRequest
21+
if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
22+
return {
23+
send: function( headers, complete ) {
24+
var i,
25+
xhr = options.xhr();
26+
// Open the socket
27+
xhr.open( options.type, options.url, options.async, options.username, options.password );
28+
// Apply custom fields if provided
29+
if ( options.xhrFields ) {
30+
for ( i in options.xhrFields ) {
31+
xhr[ i ] = options.xhrFields[ i ];
7932
}
80-
81-
// X-Requested-With header
82-
// For cross-domain requests, seeing as conditions for a preflight are
83-
// akin to a jigsaw puzzle, we simply never set it to be sure.
84-
// (it can always be set on a per-request basis or even using ajaxSetup)
85-
// For same-domain requests, won't change header if already provided.
86-
if ( !s.crossDomain && !headers["X-Requested-With"] ) {
87-
headers["X-Requested-With"] = "XMLHttpRequest";
88-
}
89-
90-
// Need an extra try/catch for cross domain requests in Firefox 3
91-
try {
92-
for ( i in headers ) {
93-
xhr.setRequestHeader( i, headers[ i ] );
94-
}
95-
} catch( err ) {}
96-
97-
// Do send the request
98-
// This may raise an exception which is actually
99-
// handled in jQuery.ajax (so no try/catch here)
100-
xhr.send( ( s.hasContent && s.data ) || null );
101-
102-
// Listener
103-
callback = function( _, isAbort ) {
104-
105-
var status,
106-
statusText,
107-
responseHeaders,
108-
responses,
109-
xml;
110-
111-
// Firefox throws exceptions when accessing properties
112-
// of an xhr when a network error occurred
113-
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
114-
try {
115-
116-
// Was never called and is aborted or complete
117-
if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
118-
119-
// Only called once
120-
callback = undefined;
121-
122-
// Do not keep as active anymore
123-
if ( handle ) {
124-
xhr.onreadystatechange = jQuery.noop;
125-
if ( xhrOnUnloadAbort ) {
126-
delete xhrCallbacks[ handle ];
127-
}
128-
}
129-
130-
// If it's an abort
131-
if ( isAbort ) {
132-
// Abort it manually if needed
133-
if ( xhr.readyState !== 4 ) {
134-
xhr.abort();
135-
}
136-
} else {
137-
responses = {};
138-
status = xhr.status;
139-
xml = xhr.responseXML;
140-
responseHeaders = xhr.getAllResponseHeaders();
141-
142-
// Construct response list
143-
if ( xml && xml.documentElement /* #4958 */ ) {
144-
responses.xml = xml;
145-
}
146-
147-
// When requesting binary data, IE6-9 will throw an exception
148-
// on any attempt to access responseText (#11426)
149-
if ( typeof xhr.responseText === "string" ) {
150-
responses.text = xhr.responseText;
151-
}
152-
153-
// Firefox throws an exception when accessing
154-
// statusText for faulty cross-domain requests
155-
try {
156-
statusText = xhr.statusText;
157-
} catch( e ) {
158-
// We normalize with Webkit giving an empty statusText
159-
statusText = "";
160-
}
161-
162-
// Filter status for non standard behaviors
163-
164-
// If the request is local and we have data: assume a success
165-
// (success with no data won't get notified, that's the best we
166-
// can do given current implementations)
167-
if ( !status && s.isLocal && !s.crossDomain ) {
168-
status = responses.text ? 200 : 404;
169-
// IE - #1450: sometimes returns 1223 when it should be 204
170-
} else if ( status === 1223 ) {
171-
status = 204;
172-
}
173-
}
174-
}
175-
} catch( firefoxAccessException ) {
176-
if ( !isAbort ) {
177-
complete( -1, firefoxAccessException );
33+
}
34+
// Override mime type if needed
35+
if ( options.mimeType && xhr.overrideMimeType ) {
36+
xhr.overrideMimeType( options.mimeType );
37+
}
38+
// X-Requested-With header
39+
// For cross-domain requests, seeing as conditions for a preflight are
40+
// akin to a jigsaw puzzle, we simply never set it to be sure.
41+
// (it can always be set on a per-request basis or even using ajaxSetup)
42+
// For same-domain requests, won't change header if already provided.
43+
if ( !options.crossDomain && !headers["X-Requested-With"] ) {
44+
headers["X-Requested-With"] = "XMLHttpRequest";
45+
}
46+
// Set headers
47+
for ( i in headers ) {
48+
xhr.setRequestHeader( i, headers[ i ] );
49+
}
50+
// Callback
51+
callback = function( type ) {
52+
return function() {
53+
if ( callback ) {
54+
callback = xhr.onload = xhr.onerror = null;
55+
if ( type === "abort" ) {
56+
xhr.abort();
57+
} else if ( type === "error" ) {
58+
complete( xhr.status, xhr.statusText );
59+
} else {
60+
complete(
61+
xhrSuccessStatus[ xhr.status ] || xhr.status,
62+
xhr.statusText,
63+
// IE - #11426: When requesting binary data, IE9 will
64+
// throw an exception on any attempt to access responseText
65+
typeof xhr.responseText === "string" ? {
66+
text: xhr.responseText
67+
} : undefined,
68+
xhr.getAllResponseHeaders()
69+
);
17870
}
17971
}
180-
181-
// Call complete if needed
182-
if ( responses ) {
183-
complete( status, statusText, responses, responseHeaders );
184-
}
18572
};
186-
187-
if ( !s.async ) {
188-
// if we're in sync mode we fire the callback
189-
callback();
190-
} else if ( xhr.readyState === 4 ) {
191-
// (IE6 & IE7) if it's in cache and has been
192-
// retrieved directly we need to fire the callback
193-
setTimeout( callback );
194-
} else {
195-
handle = ++xhrId;
196-
if ( xhrOnUnloadAbort ) {
197-
// Create the active xhrs callbacks list if needed
198-
// and attach the unload handler
199-
if ( !xhrCallbacks ) {
200-
xhrCallbacks = {};
201-
jQuery( window ).unload( xhrOnUnloadAbort );
202-
}
203-
// Add to list of active xhrs callbacks
204-
xhrCallbacks[ handle ] = callback;
205-
}
206-
xhr.onreadystatechange = callback;
207-
}
208-
},
209-
210-
abort: function() {
211-
if ( callback ) {
212-
callback( undefined, true );
213-
}
73+
};
74+
// Listen to events
75+
xhr.onload = callback();
76+
xhr.onerror = callback("error");
77+
// Create the abort callback
78+
callback = callback("abort");
79+
// Do send the request
80+
// This may raise an exception which is actually
81+
// handled in jQuery.ajax (so no try/catch here)
82+
xhr.send( options.hasContent && options.data || null );
83+
},
84+
85+
abort: function() {
86+
if ( callback ) {
87+
callback();
21488
}
215-
};
216-
}
217-
});
218-
}
89+
}
90+
};
91+
}
92+
});

test/unit/ajax.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,24 +1429,26 @@ module( "ajax", {
14291429
}
14301430
});
14311431

1432-
test( "#11743 - jQuery.ajax() - script, throws exception", 1, function() {
1433-
raises(function() {
1434-
jQuery.ajax({
1435-
url: "data/badjson.js",
1436-
dataType: "script",
1437-
throws: true,
1438-
// TODO find a way to test this asynchronously, too
1439-
async: false,
1440-
// Global events get confused by the exception
1441-
global: false,
1442-
success: function() {
1443-
ok( false, "Success." );
1444-
},
1445-
error: function() {
1446-
ok( false, "Error." );
1447-
}
1448-
});
1449-
}, "exception bubbled" );
1432+
asyncTest( "#11743 - jQuery.ajax() - script, throws exception", 1, function() {
1433+
var onerror = window.onerror;
1434+
window.onerror = function() {
1435+
ok( true, "Exception thrown" );
1436+
window.onerror = onerror;
1437+
start();
1438+
};
1439+
jQuery.ajax({
1440+
url: "data/badjson.js",
1441+
dataType: "script",
1442+
throws: true,
1443+
// Global events get confused by the exception
1444+
global: false,
1445+
success: function() {
1446+
ok( false, "Success." );
1447+
},
1448+
error: function() {
1449+
ok( false, "Error." );
1450+
}
1451+
});
14501452
});
14511453

14521454
jQuery.each( [ "method", "type" ], function( _, globalOption ) {

0 commit comments

Comments
 (0)