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

Commit 5bbd64a

Browse files
vojtajinaIgorMinar
authored andcommitted
feat($http): allow passing custom cache instance per request
You can still use cache: true, which will use $http's default cache.
1 parent caeb1bf commit 5bbd64a

File tree

2 files changed

+98
-25
lines changed

2 files changed

+98
-25
lines changed

src/service/http.js

+43-13
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ function $HttpProvider() {
9292
this.$get = ['$httpBackend', '$browser', '$exceptionHandler', '$cacheFactory', '$rootScope',
9393
function($httpBackend, $browser, $exceptionHandler, $cacheFactory, $rootScope) {
9494

95-
var cache = $cacheFactory('$http');
95+
var defaultCache = $cacheFactory('$http');
9696

9797
// the actual service
9898
function $http(config) {
@@ -226,7 +226,7 @@ function $HttpProvider() {
226226
* Represents Request object, returned by $http()
227227
*
228228
* !!! ACCESS CLOSURE VARS:
229-
* $httpBackend, $browser, $config, $log, $rootScope, cache, $http.pendingRequests
229+
* $httpBackend, $browser, $config, $log, $rootScope, defaultCache, $http.pendingRequests
230230
*/
231231
function XhrFuture() {
232232
var rawRequest, parsedHeaders,
@@ -244,9 +244,15 @@ function $HttpProvider() {
244244
// aborted request or jsonp
245245
if (!rawRequest) parsedHeaders = {};
246246

247-
if (cfg.cache && cfg.method == 'GET' && 200 <= status && status < 300) {
248-
parsedHeaders = parsedHeaders || parseHeaders(rawRequest.getAllResponseHeaders());
249-
cache.put(cfg.url, [status, response, parsedHeaders]);
247+
if (cfg.cache && cfg.method == 'GET') {
248+
var cache = isObject(cfg.cache) && cfg.cache || defaultCache;
249+
if (200 <= status && status < 300) {
250+
parsedHeaders = parsedHeaders || parseHeaders(rawRequest.getAllResponseHeaders());
251+
cache.put(cfg.url, [status, response, parsedHeaders]);
252+
} else {
253+
// remove future object from cache
254+
cache.remove(cfg.url);
255+
}
250256
}
251257

252258
fireCallbacks(response, status);
@@ -333,19 +339,43 @@ function $HttpProvider() {
333339
headers = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
334340
defHeaders.common, defHeaders[lowercase(cfg.method)], cfg.headers);
335341

336-
var fromCache;
337-
if (cfg.cache && cfg.method == 'GET' && (fromCache = cache.get(cfg.url))) {
338-
$browser.defer(function() {
339-
parsedHeaders = fromCache[2];
340-
fireCallbacks(fromCache[1], fromCache[0]);
341-
});
342-
} else {
342+
var cache = isObject(cfg.cache) && cfg.cache || defaultCache,
343+
fromCache;
344+
345+
if (cfg.cache && cfg.method == 'GET') {
346+
fromCache = cache.get(cfg.url);
347+
if (fromCache) {
348+
if (fromCache instanceof XhrFuture) {
349+
// cached request has already been sent, but there is no reponse yet,
350+
// we need to register callback and fire callbacks when the request is back
351+
// note, we have to get the values from cache and perform transformations on them,
352+
// as the configurations don't have to be same
353+
fromCache.on('always', function() {
354+
var requestFromCache = cache.get(cfg.url);
355+
parsedHeaders = requestFromCache[2];
356+
fireCallbacks(requestFromCache[1], requestFromCache[0]);
357+
});
358+
} else {
359+
// serving from cache - still needs to be async
360+
$browser.defer(function() {
361+
parsedHeaders = fromCache[2];
362+
fireCallbacks(fromCache[1], fromCache[0]);
363+
});
364+
}
365+
} else {
366+
// put future object into cache
367+
cache.put(cfg.url, self);
368+
}
369+
}
370+
371+
// really send the request
372+
if (!cfg.cache || cfg.method !== 'GET' || !fromCache) {
343373
rawRequest = $httpBackend(cfg.method, cfg.url, data, done, headers, cfg.timeout);
344374
}
345375

346376
$rootScope.$broadcast('$http.request', self);
347377
$http.pendingRequests.push(self);
348-
return this;
378+
return self;
349379
};
350380

351381
// just alias so that in stack trace we can see send() instead of retry()

test/service/httpSpec.js

+55-12
Original file line numberDiff line numberDiff line change
@@ -779,36 +779,59 @@ describe('$http', function() {
779779

780780
describe('cache', function() {
781781

782+
var cache;
783+
784+
beforeEach(inject(function($cacheFactory) {
785+
cache = $cacheFactory('testCache');
786+
}));
787+
782788
function doFirstCacheRequest(method, respStatus, headers) {
783789
$httpBackend.expect(method || 'GET', '/url').respond(respStatus || 200, 'content', headers);
784-
$http({method: method || 'GET', url: '/url', cache: true});
790+
$http({method: method || 'GET', url: '/url', cache: cache});
785791
$httpBackend.flush();
786792
}
787793

788-
it('should cache GET request', function() {
794+
it('should cache GET request when cache is provided', function() {
789795
doFirstCacheRequest();
790796

791-
$http({method: 'get', url: '/url', cache: true}).on('200', callback);
797+
$http({method: 'get', url: '/url', cache: cache}).on('200', callback);
792798
$browser.defer.flush();
793799

794800
expect(callback).toHaveBeenCalledOnce();
795801
expect(callback.mostRecentCall.args[0]).toBe('content');
796802
});
797803

798804

805+
it('should not cache when cache is not provided', function() {
806+
doFirstCacheRequest();
807+
808+
$httpBackend.expect('GET', '/url').respond();
809+
$http({method: 'GET', url: '/url'});
810+
});
811+
812+
813+
it('should perform request when cache cleared', function() {
814+
doFirstCacheRequest();
815+
816+
cache.removeAll();
817+
$httpBackend.expect('GET', '/url').respond();
818+
$http({method: 'GET', url: '/url', cache: cache});
819+
});
820+
821+
799822
it('should always call callback asynchronously', function() {
800823
doFirstCacheRequest();
801-
$http({method: 'get', url: '/url', cache: true}).on('200', callback);
824+
$http({method: 'get', url: '/url', cache: cache}).on('200', callback);
802825

803-
expect(callback).not.toHaveBeenCalledOnce();
826+
expect(callback).not.toHaveBeenCalled();
804827
});
805828

806829

807830
it('should not cache POST request', function() {
808831
doFirstCacheRequest('POST');
809832

810833
$httpBackend.expect('POST', '/url').respond('content2');
811-
$http({method: 'POST', url: '/url', cache: true}).on('200', callback);
834+
$http({method: 'POST', url: '/url', cache: cache}).on('200', callback);
812835
$httpBackend.flush();
813836

814837
expect(callback).toHaveBeenCalledOnce();
@@ -820,7 +843,7 @@ describe('$http', function() {
820843
doFirstCacheRequest('PUT');
821844

822845
$httpBackend.expect('PUT', '/url').respond('content2');
823-
$http({method: 'PUT', url: '/url', cache: true}).on('200', callback);
846+
$http({method: 'PUT', url: '/url', cache: cache}).on('200', callback);
824847
$httpBackend.flush();
825848

826849
expect(callback).toHaveBeenCalledOnce();
@@ -832,7 +855,7 @@ describe('$http', function() {
832855
doFirstCacheRequest('DELETE');
833856

834857
$httpBackend.expect('DELETE', '/url').respond(206);
835-
$http({method: 'DELETE', url: '/url', cache: true}).on('206', callback);
858+
$http({method: 'DELETE', url: '/url', cache: cache}).on('206', callback);
836859
$httpBackend.flush();
837860

838861
expect(callback).toHaveBeenCalledOnce();
@@ -843,7 +866,7 @@ describe('$http', function() {
843866
doFirstCacheRequest('GET', 404);
844867

845868
$httpBackend.expect('GET', '/url').respond('content2');
846-
$http({method: 'GET', url: '/url', cache: true}).on('200', callback);
869+
$http({method: 'GET', url: '/url', cache: cache}).on('200', callback);
847870
$httpBackend.flush();
848871

849872
expect(callback).toHaveBeenCalledOnce();
@@ -858,7 +881,7 @@ describe('$http', function() {
858881
expect(headers('server')).toBe('Apache');
859882
});
860883

861-
$http({method: 'GET', url: '/url', cache: true}).on('200', callback);
884+
$http({method: 'GET', url: '/url', cache: cache}).on('200', callback);
862885
$browser.defer.flush();
863886
expect(callback).toHaveBeenCalledOnce();
864887
});
@@ -870,10 +893,27 @@ describe('$http', function() {
870893
expect(status).toBe(201);
871894
});
872895

873-
$http({method: 'get', url: '/url', cache: true}).on('2xx', callback);
896+
$http({method: 'get', url: '/url', cache: cache}).on('2xx', callback);
874897
$browser.defer.flush();
875898
expect(callback).toHaveBeenCalledOnce();
876899
});
900+
901+
902+
it('should use cache even if request fired before first response is back', function() {
903+
$httpBackend.expect('GET', '/url').respond(201, 'fake-response');
904+
905+
callback.andCallFake(function(response, status, headers) {
906+
expect(response).toBe('fake-response');
907+
expect(status).toBe(201);
908+
});
909+
910+
$http({method: 'GET', url: '/url', cache: cache}).on('always', callback);
911+
$http({method: 'GET', url: '/url', cache: cache}).on('always', callback);
912+
913+
$httpBackend.flush();
914+
expect(callback).toHaveBeenCalled();
915+
expect(callback.callCount).toBe(2);
916+
});
877917
});
878918

879919

@@ -903,10 +943,13 @@ describe('$http', function() {
903943
});
904944

905945

906-
it('should remove the request when served from cache', function() {
946+
it('should update pending requests even when served from cache', function() {
907947
$httpBackend.when('GET').respond(200);
908948

909949
$http({method: 'get', url: '/cached', cache: true});
950+
$http({method: 'get', url: '/cached', cache: true});
951+
expect($http.pendingRequests.length).toBe(2);
952+
910953
$httpBackend.flush();
911954
expect($http.pendingRequests.length).toBe(0);
912955

0 commit comments

Comments
 (0)