12

Is there a way to remove a scope from the digest cycles? In other words, to suspend/resume a scope digest cycle?

In my case, I have all pages already loaded, but not all of them visible. So I'd like to suspend the ones that aren't visible to avoid useless processing. I don't want to use ng-view + $route, I don't want/need deep-linking.

I saw this thread and arrived to this fiddle. It probably does the work, but it's pretty invasive and not very framework-update-friendly.

Is there any other solution like a $scope.suspend() and scope.resume()? Or a less invasive one (from framework perspective)? I'm currently thinking about $destroy and $compile cycles.

Caio Cunha
  • 23,326
  • 6
  • 78
  • 74

2 Answers2

12

I've ran into the same problem and I found an interesting solution that doesn't interfere (too much) with AngularJS. Add this to the scopes you want to disable:

var watchers;

scope.$on('suspend', function () {
  watchers = scope.$$watchers;
  scope.$$watchers = [];
});

scope.$on('resume', function () {
  scope.$$watchers = watchers;
  watchers = null;
});

Then, you can disable a scope and its children with: scope.$broadcast('suspend') and bring it back with scope.$broadcast('resume').

Laurent Perrin
  • 14,671
  • 5
  • 50
  • 49
  • Nice trick. This would certainly do the trick, although I don't like hacks pretty well as it make harder to upgrade versions. Anyway, if anyone would use this approach, it would be nice to also override override `$scope.$watch`, as new watchers might be added while disabled. – Caio Cunha Jul 26 '13 at 13:45
  • I've just posted a short article about this technique: https://coderwall.com/p/d_aisq – Laurent Perrin Jul 03 '14 at 17:28
  • this just saved me with an app that had a non-performant table that's not visible all the time. the long solution is to paginate the sortable table and make infinite scroll... but this kicks that can down the road so we can focus on more important features due right now. nice. woo tech debt! – FlavorScape Jan 04 '16 at 02:43
3

As the framework stands today there are no methods to suspend / resume digest on a scope. Having said this there are several techniques that one can use to limit number of watches that are executed as part of a digest cycle.

First of all, if parts of a screen are hidden anyway you could use the ng-switch family of directives thus removing invisible parts completely from the DOM.

Secondly, if a digest cycle is triggered from your directive via $apply and you want to limit watches re-evaluation to child scopes you could call $digest instead of $apply.

Then, yes, one could destroy and re-create scopes as described in the discussion you've linked to. But, if you are already hiding parts of the DOM it sounds like ng-switch might be a better option.

pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
  • Using `ng-switch` is a considerable option for this use case indeed. But don't you believe it's reasonable that someone using non-angular code would wish to suspend updates on a certain part of the DOM without letting `ng-switch` control the manipulation? We could certainly mimic `ng-switch` behavior, but seems that this is a key feature for performance tuning on big hybrid projects. Moreover, maybe a way to prevent `ng-bind` watches to run only. Don't know... share your thoughts please. – Caio Cunha Feb 01 '13 at 16:45