Is there a way to disable triggering of $digest on every $http.get?
Asked Answered
G

2

9

Background

angular's $http service is triggering a $digest on every get (if no $digest is already running):

if (!$rootScope.$$phase) $rootScope.$apply();  

Ia addition to fetching objects from our API, our app has many directives with templateUrl - which are fetched by angular using $http. This causes hundreds of $digest loops on cold start.

Commenting out the above line, reduces the number of $digest loops to about 3, and the app runs MUCH faster, with no bindings broken (at least due to $http not triggering a $digest).

Question

Is there a way to disable $http triggering the $digest?

Gonnella answered 28/8, 2014 at 12:56 Comment(12)
Some interesting thoughts if you haven't checked that already.Brenza
Why not skip the HTTP calls altogether? - Use the $templateCache. (Or am I mistaking and $apply is called even if no AJAX request has to be sent?)Spodumene
@Brenza - Thanks, but we can't move to WebSockets at the moment, and we hacking the watchers list won't help in this case.Gonnella
@SergiuParaschiv - Thanks, but we already do that. We even store the templates in the localStorage using angular-cache. I still doesn't help in a "cold start" scenario, which is very important to us.Gonnella
Turns out $templateCache is implemented at a lower level and the $apply is called even if the template is already in the cache. But looking at the sources I see this line: github.com/angular/angular.js/blob/master/src/ng/http.js#L984 Is useApplyAsync not doing the job?Spodumene
Oh...it's a six days old commit: github.com/angular/angular.js/commit/… :) But I think this should do the trick in your case.Spodumene
@SergiuParaschiv - We use the latest beta.. I guess it is not edgy enough :-) But even if we has that feature, I think it would only aggregate gets in ~10msec batches, which I believe is still not enough.Gonnella
@SergiuParaschiv done is only called when the object is not cached and a request is sent: if (isUndefined(cachedResp)) { $httpBackend(config.method, url, reqData, doneGurdwara
Again, at a cold start (nothing is cached), we still have to fetch X templates + Y objects. We try to keep X+Y to a minimum, but it is still very significant.Gonnella
That's not what I meant by using $templateCache. I'm talking about this: npmjs.org/package/grunt-angular-templates BUT the template parameter on directives accepts a function. Check this out: plnkr.co/edit/ilffq2JkaziAOX6wUGJf?p=preview It completely bypasses templateUrl and a single $apply is called. Inside it you can get the actual template from localStorage.Spodumene
@SergiuParaschiv - Yeah, we don't use node, and still, it solves only the templateUrl issue. We also have many objects fetched from an API, which can't preload... templateUrl is just half of the problem's effects.Gonnella
Then don't use $http.Spodumene
I
3

use $httpProvider.useApplyAsync(true); on app config. then the templates directive loaded within 10ms will face the same digest. this will reduce the digest cycle call. see here

Inapprehensible answered 31/1, 2016 at 5:32 Comment(0)
B
0

It may not be possible to do what you want directly, but you can limit the impact of those digest cycles. Try putting a <div ng-if="everythingLoaded"> around most of the page, and set everythingLoaded to true after all of your $http calls complete.

For example:

var p1 = $http.get(...);
var p2 = $http.get(...);
Promises.all([p1, p2]).then(function() {
  $scope.everythingLoaded = true;
});

The digest cycle will still run but will be much faster because the ng-if will eliminate the impact on the DOM and much of your controller until the condition becomes true.

I'm pretty sure using template caching will solve for the template loading problem, assuming it is still a problem in recent angular versions.

Bedstead answered 24/11, 2015 at 0:15 Comment(3)
Just for your information in case you didn't notice, this question was presented more than a year ago. The angular releases have changed drastically in the past year, and though your answer may be correct, you might want to review it to ensure what angular versions this would apply to.Forceps
@Forceps this is pretty straightforward and is valid all the way to 1.5.9 (current). Stuff hidden behind an ng-if won't be digested because it doesn't exist in the DOM at the moment a digest is triggered.Courser
@Courser I'm sure that's the case. This comment is now about a year old comment to a two year old question, and the only point I was trying to make at that time was that answering a year old question is something that should involve more scrutiny, since it is much more likely to be relevant to others than to the original poster.Forceps

© 2022 - 2024 — McMap. All rights reserved.