Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 75d4f47

Browse files
realitykingIgorMinar
authored andcommitted
refactor($http) Use onload/onerror/onabort instead of onreadystatechange
1 parent 02afa0c commit 75d4f47

File tree

2 files changed

+39
-131
lines changed

2 files changed

+39
-131
lines changed

src/ng/httpBackend.js

+28-48
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@ function $HttpBackendProvider() {
2727
}
2828

2929
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
30-
var ABORTED = -1;
31-
3230
// TODO(vojta): fix the signature
3331
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
34-
var status;
3532
$browser.$$incOutstandingRequestCount();
3633
url = url || $browser.url();
3734

@@ -58,44 +55,39 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
5855
}
5956
});
6057

61-
// In IE6 and 7, this might be called synchronously when xhr.send below is called and the
62-
// response is in the cache. the promise api will ensure that to the app code the api is
63-
// always async
64-
xhr.onreadystatechange = function() {
65-
// onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
66-
// xhrs that are resolved while the app is in the background (see #5426).
67-
// since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
68-
// continuing
69-
//
70-
// we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
71-
// Safari respectively.
72-
if (xhr && xhr.readyState == 4) {
73-
var responseHeaders = null,
74-
response = null,
75-
statusText = '';
76-
77-
if(status !== ABORTED) {
78-
responseHeaders = xhr.getAllResponseHeaders();
79-
80-
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
81-
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
82-
response = ('response' in xhr) ? xhr.response : xhr.responseText;
83-
}
58+
xhr.onload = function requestComplete() {
59+
var statusText = xhr.statusText || '';
8460

85-
// Accessing statusText on an aborted xhr object will
86-
// throw an 'c00c023f error' in IE9 and lower, don't touch it.
87-
if (!(status === ABORTED && msie < 10)) {
88-
statusText = xhr.statusText;
89-
}
61+
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
62+
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
63+
var response = ('response' in xhr) ? xhr.response : xhr.responseText;
9064

91-
completeRequest(callback,
92-
status || xhr.status,
93-
response,
94-
responseHeaders,
95-
statusText);
65+
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
66+
var status = xhr.status === 1223 ? 204 : xhr.status;
67+
68+
// fix status code when it is 0 (0 status is undocumented).
69+
// Occurs when accessing file resources or on Android 4.1 stock browser
70+
// while retrieving files from application cache.
71+
if (status === 0) {
72+
status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
9673
}
74+
75+
completeRequest(callback,
76+
status,
77+
response,
78+
xhr.getAllResponseHeaders(),
79+
statusText);
9780
};
9881

82+
var requestError = function () {
83+
// The response is always empty
84+
// See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
85+
completeRequest(callback, -1, null, null, '');
86+
};
87+
88+
xhr.onerror = requestError;
89+
xhr.onabort = requestError;
90+
9991
if (withCredentials) {
10092
xhr.withCredentials = true;
10193
}
@@ -128,7 +120,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
128120

129121

130122
function timeoutRequest() {
131-
status = ABORTED;
132123
jsonpDone && jsonpDone();
133124
xhr && xhr.abort();
134125
}
@@ -138,17 +129,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
138129
timeoutId && $browserDefer.cancel(timeoutId);
139130
jsonpDone = xhr = null;
140131

141-
// fix status code when it is 0 (0 status is undocumented).
142-
// Occurs when accessing file resources or on Android 4.1 stock browser
143-
// while retrieving files from application cache.
144-
if (status === 0) {
145-
status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
146-
}
147-
148-
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
149-
status = status === 1223 ? 204 : status;
150-
statusText = statusText || '';
151-
152132
callback(status, response, headersString, statusText);
153133
$browser.$$completeOutstandingRequest(noop);
154134
}

test/ng/httpBackendSpec.js

+11-83
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,7 @@ describe('$httpBackend', function() {
8787
$backend('GET', '/some-url', null, callback);
8888
xhr = MockXhr.$$lastInstance;
8989
xhr.statusText = 'OK';
90-
xhr.readyState = 4;
91-
xhr.onreadystatechange();
92-
expect(callback).toHaveBeenCalledOnce();
93-
});
94-
95-
it('should not touch xhr.statusText when request is aborted on IE9 or lower', function() {
96-
callback.andCallFake(function(status, response, headers, statusText) {
97-
expect(statusText).toBe((!msie || msie >= 10) ? 'OK' : '');
98-
});
99-
100-
$backend('GET', '/url', null, callback, {}, 2000);
101-
xhr = MockXhr.$$lastInstance;
102-
spyOn(xhr, 'abort');
103-
104-
fakeTimeout.flush();
105-
expect(xhr.abort).toHaveBeenCalledOnce();
106-
107-
xhr.status = 0;
108-
xhr.readyState = 4;
109-
xhr.statusText = 'OK';
110-
xhr.onreadystatechange();
90+
xhr.onload();
11191
expect(callback).toHaveBeenCalledOnce();
11292
});
11393

@@ -118,8 +98,7 @@ describe('$httpBackend', function() {
11898

11999
$backend('GET', '/some-url', null, callback);
120100
xhr = MockXhr.$$lastInstance;
121-
xhr.readyState = 4;
122-
xhr.onreadystatechange();
101+
xhr.onload();
123102
expect(callback).toHaveBeenCalledOnce();
124103
});
125104

@@ -133,23 +112,7 @@ describe('$httpBackend', function() {
133112
xhr = MockXhr.$$lastInstance;
134113

135114
xhr.status = 1223;
136-
xhr.readyState = 4;
137-
xhr.onreadystatechange();
138-
139-
expect(callback).toHaveBeenCalledOnce();
140-
});
141-
142-
// onreadystatechange might by called multiple times
143-
// with readyState === 4 on mobile webkit caused by
144-
// xhrs that are resolved while the app is in the background (see #5426).
145-
it('should not process onreadystatechange callback with readyState == 4 more than once', function() {
146-
$backend('GET', 'URL', null, callback);
147-
xhr = MockXhr.$$lastInstance;
148-
149-
xhr.status = 200;
150-
xhr.readyState = 4;
151-
xhr.onreadystatechange();
152-
xhr.onreadystatechange();
115+
xhr.onload();
153116

154117
expect(callback).toHaveBeenCalledOnce();
155118
});
@@ -195,8 +158,7 @@ describe('$httpBackend', function() {
195158
expect(xhr.abort).toHaveBeenCalledOnce();
196159

197160
xhr.status = 0;
198-
xhr.readyState = 4;
199-
xhr.onreadystatechange();
161+
xhr.onabort();
200162
expect(callback).toHaveBeenCalledOnce();
201163
});
202164

@@ -215,8 +177,7 @@ describe('$httpBackend', function() {
215177
expect(xhr.abort).toHaveBeenCalledOnce();
216178

217179
xhr.status = 0;
218-
xhr.readyState = 4;
219-
xhr.onreadystatechange();
180+
xhr.onabort();
220181
expect(callback).toHaveBeenCalledOnce();
221182
});
222183

@@ -234,8 +195,7 @@ describe('$httpBackend', function() {
234195
expect(xhr.abort).toHaveBeenCalledOnce();
235196

236197
xhr.status = 0;
237-
xhr.readyState = 4;
238-
xhr.onreadystatechange();
198+
xhr.onabort();
239199
expect(callback).toHaveBeenCalledOnce();
240200
}));
241201

@@ -250,8 +210,7 @@ describe('$httpBackend', function() {
250210
spyOn(xhr, 'abort');
251211

252212
xhr.status = 200;
253-
xhr.readyState = 4;
254-
xhr.onreadystatechange();
213+
xhr.onload();
255214
expect(callback).toHaveBeenCalledOnce();
256215

257216
$timeout.flush();
@@ -271,42 +230,14 @@ describe('$httpBackend', function() {
271230
expect(fakeTimeout.delays[0]).toBe(2000);
272231

273232
xhr.status = 200;
274-
xhr.readyState = 4;
275-
xhr.onreadystatechange();
233+
xhr.onload();
276234
expect(callback).toHaveBeenCalledOnce();
277235

278236
expect(fakeTimeout.delays.length).toBe(0);
279237
expect(xhr.abort).not.toHaveBeenCalled();
280238
});
281239

282240

283-
it('should register onreadystatechange callback before sending', function() {
284-
// send() in IE6, IE7 is sync when serving from cache
285-
function SyncXhr() {
286-
xhr = this;
287-
this.open = this.setRequestHeader = noop;
288-
289-
this.send = function() {
290-
this.status = 200;
291-
this.responseText = 'response';
292-
this.readyState = 4;
293-
this.onreadystatechange();
294-
};
295-
296-
this.getAllResponseHeaders = valueFn('');
297-
}
298-
299-
callback.andCallFake(function(status, response) {
300-
expect(status).toBe(200);
301-
expect(response).toBe('response');
302-
});
303-
304-
$backend = createHttpBackend($browser, function() { return new SyncXhr(); });
305-
$backend('GET', '/url', null, callback);
306-
expect(callback).toHaveBeenCalledOnce();
307-
});
308-
309-
310241
it('should set withCredentials', function() {
311242
$backend('GET', '/some.url', null, callback, {}, null, true);
312243
expect(MockXhr.$$lastInstance.withCredentials).toBe(true);
@@ -326,8 +257,7 @@ describe('$httpBackend', function() {
326257
});
327258

328259
xhrInstance.response = {some: 'object'};
329-
xhrInstance.readyState = 4;
330-
xhrInstance.onreadystatechange();
260+
xhrInstance.onload();
331261

332262
expect(callback).toHaveBeenCalledOnce();
333263
});
@@ -347,8 +277,7 @@ describe('$httpBackend', function() {
347277
});
348278

349279
xhrInstance.responseText = responseText;
350-
xhrInstance.readyState = 4;
351-
xhrInstance.onreadystatechange();
280+
xhrInstance.onload();
352281

353282
expect(callback).toHaveBeenCalledOnce();
354283
});
@@ -436,8 +365,7 @@ describe('$httpBackend', function() {
436365
xhr = MockXhr.$$lastInstance;
437366
xhr.status = status;
438367
xhr.responseText = content;
439-
xhr.readyState = 4;
440-
xhr.onreadystatechange();
368+
xhr.onload();
441369
}
442370

443371

0 commit comments

Comments
 (0)