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

Commit c2e24b9

Browse files
committed
refactor($http): remove unneeded call to $apply
1 parent ad4296d commit c2e24b9

File tree

4 files changed

+33
-99
lines changed

4 files changed

+33
-99
lines changed

src/ng/http.js

+4-43
Original file line numberDiff line numberDiff line change
@@ -308,34 +308,6 @@ function $HttpProvider() {
308308
paramSerializer: '$httpParamSerializer'
309309
};
310310

311-
var useApplyAsync = false;
312-
/**
313-
* @ngdoc method
314-
* @name $httpProvider#useApplyAsync
315-
* @description
316-
*
317-
* Configure $http service to combine processing of multiple http responses received at around
318-
* the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
319-
* significant performance improvement for bigger applications that make many HTTP requests
320-
* concurrently (common during application bootstrap).
321-
*
322-
* Defaults to false. If no value is specified, returns the current configured value.
323-
*
324-
* @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
325-
* "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
326-
* to load and share the same digest cycle.
327-
*
328-
* @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
329-
* otherwise, returns the current configured value.
330-
**/
331-
this.useApplyAsync = function(value) {
332-
if (isDefined(value)) {
333-
useApplyAsync = !!value;
334-
return this;
335-
}
336-
return useApplyAsync;
337-
};
338-
339311
var useLegacyPromise = true;
340312
/**
341313
* @ngdoc method
@@ -375,8 +347,8 @@ function $HttpProvider() {
375347
**/
376348
var interceptorFactories = this.interceptors = [];
377349

378-
this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
379-
function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
350+
this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$q', '$injector',
351+
function($httpBackend, $$cookieReader, $cacheFactory, $q, $injector) {
380352

381353
var defaultCache = $cacheFactory('$http');
382354

@@ -404,7 +376,6 @@ function $HttpProvider() {
404376
* @name $http
405377
* @requires ng.$httpBackend
406378
* @requires $cacheFactory
407-
* @requires $rootScope
408379
* @requires $q
409380
* @requires $injector
410381
*
@@ -1189,7 +1160,7 @@ function $HttpProvider() {
11891160
* Makes the request.
11901161
*
11911162
* !!! ACCESSES CLOSURE VARS:
1192-
* $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
1163+
* $httpBackend, defaults, $log, defaultCache, $http.pendingRequests
11931164
*/
11941165
function sendReq(config, reqData) {
11951166
var deferred = $q.defer(),
@@ -1252,7 +1223,6 @@ function $HttpProvider() {
12521223
* Callback registered to $httpBackend():
12531224
* - caches the response if desired
12541225
* - resolves the raw $http promise
1255-
* - calls $apply
12561226
*/
12571227
function done(status, response, headersString, statusText) {
12581228
if (cache) {
@@ -1264,16 +1234,7 @@ function $HttpProvider() {
12641234
}
12651235
}
12661236

1267-
function resolveHttpPromise() {
1268-
resolvePromise(response, status, headersString, statusText);
1269-
}
1270-
1271-
if (useApplyAsync) {
1272-
$rootScope.$applyAsync(resolveHttpPromise);
1273-
} else {
1274-
resolveHttpPromise();
1275-
if (!$rootScope.$$phase) $rootScope.$apply();
1276-
}
1237+
resolvePromise(response, status, headersString, statusText);
12771238
}
12781239

12791240

src/ngMock/angular-mocks.js

+4
Original file line numberDiff line numberDiff line change
@@ -1697,10 +1697,14 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
16971697
while (count--) {
16981698
if (!responses.length) throw new Error('No more pending request to flush !');
16991699
responses.shift()();
1700+
// Calling $digest again to execute the callbacks of the promises returned from $http
1701+
// as these callbacks can add new requests to the queue to flush.
1702+
if (digest !== false) $rootScope.$digest();
17001703
}
17011704
} else {
17021705
while (responses.length) {
17031706
responses.shift()();
1707+
if (digest !== false) $rootScope.$digest();
17041708
}
17051709
}
17061710
$httpBackend.verifyNoOutstandingExpectation(digest);

test/ng/directive/ngIncludeSpec.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -360,18 +360,23 @@ describe('ngInclude', function() {
360360

361361
it('should construct SVG template elements with correct namespace', function() {
362362
if (!window.SVGRectElement) return;
363-
module(function($compileProvider) {
363+
module(function($compileProvider, $provide) {
364364
$compileProvider.directive('test', valueFn({
365365
templateNamespace: 'svg',
366366
templateUrl: 'my-rect.html',
367367
replace: true
368368
}));
369+
$provide.decorator('$templateRequest', function($delegate) {
370+
return jasmine.createSpy('$templateRequest').andCallFake($delegate);
371+
});
369372
});
370-
inject(function($compile, $rootScope, $httpBackend) {
373+
inject(function($compile, $rootScope, $httpBackend, $templateRequest) {
371374
$httpBackend.expectGET('my-rect.html').respond('<g ng-include="\'include.svg\'"></g>');
372375
$httpBackend.expectGET('include.svg').respond('<rect></rect><rect></rect>');
373376
element = $compile('<svg><test></test></svg>')($rootScope);
374-
$httpBackend.flush();
377+
expect($templateRequest.calls.length).toBe(1);
378+
$httpBackend.flush(2);
379+
expect($templateRequest.calls.length).toBe(2);
375380
var child = element.find('rect');
376381
expect(child.length).toBe(2);
377382
expect(child[0] instanceof SVGRectElement).toBe(true);

test/ng/httpSpec.js

+17-53
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ describe('$http', function() {
293293
$httpBackend = $hb;
294294
$http = $h;
295295
$rootScope = $rs;
296-
spyOn($rootScope, '$apply').andCallThrough();
296+
spyOn($rootScope, '$digest').andCallThrough();
297297
}]));
298298

299299
it('should throw error if the request configuration is not an object', function() {
@@ -1012,37 +1012,6 @@ describe('$http', function() {
10121012
});
10131013

10141014

1015-
describe('scope.$apply', function() {
1016-
1017-
it('should $apply after success callback', function() {
1018-
$httpBackend.when('GET').respond(200);
1019-
$http({method: 'GET', url: '/some'});
1020-
$httpBackend.flush();
1021-
expect($rootScope.$apply).toHaveBeenCalledOnce();
1022-
});
1023-
1024-
1025-
it('should $apply after error callback', function() {
1026-
$httpBackend.when('GET').respond(404);
1027-
$http({method: 'GET', url: '/some'});
1028-
$httpBackend.flush();
1029-
expect($rootScope.$apply).toHaveBeenCalledOnce();
1030-
});
1031-
1032-
1033-
it('should $apply even if exception thrown during callback', inject(function($exceptionHandler) {
1034-
$httpBackend.when('GET').respond(200);
1035-
callback.andThrow('error in callback');
1036-
1037-
$http({method: 'GET', url: '/some'}).then(callback);
1038-
$httpBackend.flush();
1039-
expect($rootScope.$apply).toHaveBeenCalledOnce();
1040-
1041-
$exceptionHandler.errors = [];
1042-
}));
1043-
});
1044-
1045-
10461015
describe('transformData', function() {
10471016

10481017
describe('request', function() {
@@ -1900,35 +1869,27 @@ describe('$http', function() {
19001869
});
19011870

19021871

1903-
describe('$http with $applyAsync', function() {
1904-
var $http, $httpBackend, $rootScope, $browser, log;
1905-
beforeEach(module(function($httpProvider) {
1906-
$httpProvider.useApplyAsync(true);
1907-
}, provideLog));
1908-
1872+
describe('$http interacting with digest cycle', function() {
1873+
var $http, $httpBackend, $browser, log;
1874+
beforeEach(module(provideLog));
19091875

1910-
beforeEach(inject(['$http', '$httpBackend', '$rootScope', '$browser', 'log', function(http, backend, scope, browser, logger) {
1876+
beforeEach(inject(['$http', '$httpBackend', '$browser', 'log', function(http, backend, browser, logger) {
19111877
$http = http;
19121878
$httpBackend = backend;
1913-
$rootScope = scope;
19141879
$browser = browser;
1915-
spyOn($rootScope, '$apply').andCallThrough();
1916-
spyOn($rootScope, '$applyAsync').andCallThrough();
1917-
spyOn($rootScope, '$digest').andCallThrough();
1918-
spyOn($browser.defer, 'cancel').andCallThrough();
19191880
log = logger;
19201881
}]));
19211882

19221883

1923-
it('should schedule coalesced apply on response', function() {
1884+
it('should execute callbacks asynchronously in $digest', function() {
19241885
var handler = jasmine.createSpy('handler');
19251886
$httpBackend.expect('GET', '/template1.html').respond(200, '<h1>Header!</h1>', {});
19261887
$http.get('/template1.html').then(handler);
1927-
// Ensure requests are sent
1928-
$rootScope.$digest();
1888+
// Ensure requests are sent. ($http is internally promise-based and doesn't start working until
1889+
// $digest occurs.)
1890+
$browser.defer.flush();
19291891

19301892
$httpBackend.flush(null, false);
1931-
expect($rootScope.$applyAsync).toHaveBeenCalledOnce();
19321893
expect(handler).not.toHaveBeenCalled();
19331894

19341895
$browser.defer.flush();
@@ -1943,11 +1904,14 @@ describe('$http with $applyAsync', function() {
19431904
$http.get('/template1.html').then(log.fn('response 1'));
19441905
$http.get('/template2.html').then(log.fn('response 2'));
19451906
// Ensure requests are sent
1946-
$rootScope.$digest();
1907+
$browser.defer.flush();
19471908

1909+
// Resolve the promises. When a $q promise is resolved it uses $rootScope.$evalAsync to schedule
1910+
// the execution of its callbacks.
19481911
$httpBackend.flush(null, false);
19491912
expect(log).toEqual([]);
19501913

1914+
// Execute the promises' callbacks in the $digest scheduled with $evalAsync
19511915
$browser.defer.flush();
19521916
expect(log).toEqual(['response 1', 'response 2']);
19531917
});
@@ -1961,16 +1925,16 @@ describe('$http with $applyAsync', function() {
19611925
$http.get('/template1.html').then(log.fn('response 1'));
19621926
$http.get('/template2.html').then(log.fn('response 2'));
19631927
$http.get('/template3.html').then(log.fn('response 3'));
1964-
// Ensure requests are sent
1965-
$rootScope.$digest();
19661928

19671929
// Intermediate $digest occurs before 3rd response is received, assert that pending responses
1968-
/// are handled
1930+
// are handled. Unless false is passed as the second parameter, $httpBackend.flush calls
1931+
// $rootScope.$digest at least twice (before and after doing the flush).
19691932
$httpBackend.flush(2);
19701933
expect(log).toEqual(['response 1', 'response 2']);
19711934

1972-
// Finally, third response is received, and a second coalesced $apply is started
1935+
// Finally, third response is received, and its callback is scheduled with $evalAsync
19731936
$httpBackend.flush(null, false);
1937+
// Execute the promises' callbacks in the $digest scheduled with $evalAsync
19741938
$browser.defer.flush();
19751939
expect(log).toEqual(['response 1', 'response 2', 'response 3']);
19761940
});

0 commit comments

Comments
 (0)