Skip to content

Commit fb16ce9

Browse files
author
David Bennett
committed
Added new feature to abort a pending request. Fixes issue angular#1159.
1 parent a03e370 commit fb16ce9

File tree

4 files changed

+74
-6
lines changed

4 files changed

+74
-6
lines changed

Diff for: src/ng/http.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ function $HttpProvider() {
479479
reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
480480
defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
481481
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
482-
promise;
482+
promise, abortFn;
483483

484484
// strip content-type if data is undefined
485485
if (isUndefined(config.data)) {
@@ -489,13 +489,17 @@ function $HttpProvider() {
489489
// send request
490490
promise = sendReq(config, reqData, reqHeaders);
491491

492+
// save a reference to the abort function
493+
abortFn = promise.abort;
492494

493495
// transform future response
494496
promise = promise.then(transformResponse, transformResponse);
497+
promise.abort = abortFn;
495498

496499
// apply interceptors
497500
forEach(responseInterceptors, function(interceptor) {
498501
promise = interceptor(promise);
502+
promise.abort = abortFn;
499503
});
500504

501505
promise.success = function(fn) {
@@ -661,13 +665,20 @@ function $HttpProvider() {
661665
function sendReq(config, reqData, reqHeaders) {
662666
var deferred = $q.defer(),
663667
promise = deferred.promise,
668+
abortFn,
664669
cache,
665670
cachedResp,
666671
url = buildUrl(config.url, config.params);
667672

668673
$http.pendingRequests.push(config);
669674
promise.then(removePendingReq, removePendingReq);
670675

676+
promise.abort = function() {
677+
if (isFunction(abortFn)) {
678+
abortFn();
679+
}
680+
}
681+
671682

672683
if (config.cache && config.method == 'GET') {
673684
cache = isObject(config.cache) ? config.cache : defaultCache;
@@ -696,7 +707,7 @@ function $HttpProvider() {
696707

697708
// if we won't have the response in cache, send the request to the backend
698709
if (!cachedResp) {
699-
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
710+
abortFn = $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
700711
config.withCredentials);
701712
}
702713

Diff for: src/ng/httpBackend.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,15 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
7777
xhr.send(post || '');
7878

7979
if (timeout > 0) {
80-
$browserDefer(function() {
81-
status = -1;
82-
xhr.abort();
83-
}, timeout);
80+
$browserDefer(abortRequest, timeout);
8481
}
82+
83+
return abortRequest;
84+
85+
function abortRequest() {
86+
status = -1;
87+
xhr.abort();
88+
};
8589
}
8690

8791

Diff for: test/ng/httpBackendSpec.js

+21
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,27 @@ describe('$httpBackend', function() {
8181
});
8282

8383

84+
it('should return an abort function', function() {
85+
callback.andCallFake(function(status, response) {
86+
expect(status).toBe(-1);
87+
});
88+
89+
var abort = $backend('GET', '/url', null, callback);
90+
xhr = MockXhr.$$lastInstance;
91+
spyOn(xhr, 'abort');
92+
93+
expect(typeof abort).toBe('function');
94+
95+
abort();
96+
expect(xhr.abort).toHaveBeenCalledOnce();
97+
98+
xhr.status = 0;
99+
xhr.readyState = 4;
100+
xhr.onreadystatechange();
101+
expect(callback).toHaveBeenCalledOnce();
102+
});
103+
104+
84105
it('should abort request on timeout', function() {
85106
callback.andCallFake(function(status, response) {
86107
expect(status).toBe(-1);

Diff for: test/ng/httpSpec.js

+32
Original file line numberDiff line numberDiff line change
@@ -978,4 +978,36 @@ describe('$http', function() {
978978

979979
$httpBackend.verifyNoOutstandingExpectation = noop;
980980
});
981+
982+
983+
it('should abort pending requests', function() {
984+
var $httpBackend = jasmine.createSpy('$httpBackend');
985+
var abortFn = jasmine.createSpy('abortFn');
986+
987+
$httpBackend.andCallFake(function(m, u, d, callback) {
988+
abortFn.andCallFake(function() {
989+
callback(-1, 'bad error', '');
990+
});
991+
return abortFn;
992+
});
993+
994+
module(function($provide) {
995+
$provide.value('$httpBackend', $httpBackend, '');
996+
});
997+
998+
inject(function($http) {
999+
$http({method: 'GET', url: 'some.html'}).error(function(data, status, headers, config) {
1000+
expect(data).toBe('bad error');
1001+
expect(status).toBe(0);
1002+
expect(headers()).toEqual({});
1003+
expect(config.url).toBe('some.html');
1004+
callback();
1005+
}).abort();
1006+
expect($httpBackend).toHaveBeenCalledOnce();
1007+
expect(abortFn).toHaveBeenCalledOnce();
1008+
expect(callback).toHaveBeenCalledOnce();
1009+
});
1010+
1011+
$httpBackend.verifyNoOutstandingExpectation = noop;
1012+
});
9811013
});

0 commit comments

Comments
 (0)