0

I'm encountering performance issues, I think due to lots of watchers in the page (more than 4000!!). The scenario is a (small, about 5) list of items in ng-repeat once, each one contains another ng-repeat for every day of week (so 7), and in each day container there are 1 or 2 input field. Each day's element has its own scope and controller and some watch at parent's properties, in order to update parent state at child changes. So a bit complex scenario...imagine an agenda view where each day as some input fields or buttons which update same property in the main scope, like "10 days selected/filled/clicked".

I started with about 5000 watchers, now reduced to about 4000 removing some filters and switching to translate-once directive insted of translate (angular-translate).

So the main question is:

How to further reduce the number of watchers?

Is every child scope inheriting the parent watchers, resulting in 7x for each watcher? If I remove child's controllers, leaving the job to the the parent (passing in the function the child item), will I decrease the number of watchers? Could this be a solution? Any help is appreciate.

s1moner3d
  • 1,141
  • 2
  • 16
  • 35

2 Answers2

1

In our experience that number of watchers cause no speed problems. The performance problems we have encountered in the last 8 months of development on a single big application were caused by slow third part's components.

For example, we have a page with two drag and drop trees with 14.600 watchers (because of high number of items in both trees). We experienced performance problems because of the component used, angular-ui-tree, and we reduced them opening the page with most of the tree collapsed.

We cannot change that component because it is the only one which features drag and drop between trees, but in another page where we had drag & drop between simple lists we have tried those two components: angular-dragdrop and angular-drag-and-drop-lists. The first had a lot of performance problems (with about 500 items) while the second run really really fast. In his documentation on github, section "Why another drag & drop library?" you can read why it is so fast and why the other is so slow.

So, I can speculate that third part's components bring you the real performance problems, and not the watchers.

In any case, we often write our watchers with a check like the one below to not run the code unless needed.

$scope.$watch('variableToWatch', function(newValue, oldValue) {
    if (newValue === oldValue) {
        return;
    }

    ... watcher code ...
}

Another way to reduce watchers from html is using one-time-binding. Example:

<div ng-if="::vm.user.loggedIn"></div>
McGiogen
  • 654
  • 8
  • 17
  • Yes, I already use _otb_ where possibile, decreasing the initial number of whatchers a little bit (from about 5k to about 4k), but not enough. Also tried to disable `$scope.$watch`es, with no real benefits, because we noticed that the most number of watchers are the _internal ones_, that is the internal Angular binding in the html... And the only third-party libraries we use are _angular-material_ and _angular-translate_, so I don't think the issue is due to 3rd parties. – s1moner3d Apr 05 '16 at 13:56
  • You could try [angular-translate-once](https://github.com/ajwhite/angular-translate-once), but I've seen it today casually and we still haven't tried it – McGiogen Apr 05 '16 at 15:41
  • As I wrote in the main question, we *already* use _angular-translate-once_, but still have about 4k watchers – s1moner3d Apr 05 '16 at 16:09
  • Have you tried to use events instead of watchers? It could be more complicated, but you will be sure that any line of code is ran only when needed. [See this question for some examples](http://stackoverflow.com/questions/14502006/working-with-scope-emit-and-on) – McGiogen Apr 11 '16 at 09:42
0

Related to performance... - One pattern i came up with is to use a private object and assign the prototype of a function for easy access. then in any function ,controllers, directives...ect you can access the prototype of other function,controllers,directives easily. instead of using watchers you can use this pattern like a event loop. instead of angular running 300+ watchers every digest cycles. using this pattern only what triggers the function call matters.

An example of this pattern

var private = {} //accesable to entire app


var app = angular.module('some-app',[])
.controller('someCtrl',['$scope',someCtrl])
.directive('someDirective',someDirective);

function someCtrl($scope){
private.someCtrl = someCtrl.prototype



someCtrl.prototype.update = function(someDate){
//do something....
//access to someCtrl arguments  
  
  $scope.something = someDate
}


}

function someDirective(){

  var someCtrlProto = private.someCtrl;
return{
  link:function(scope ,elm ,attr){
  
    elm[0].addEventListener('click',fucntion(){
           someCtrlProto.update(someData) 
    
      });
      //or
    
    elm[0].addEventListener('click',someCtrlProto.update) //to trigger someCtrl.update from here
    }
  }
}
echopeak
  • 251
  • 1
  • 2
  • 9
  • I'm not sure I've completely understood what you mean. In the following scenario: agenda view where in each day cell there is button for "close/open" the day, and when all days of week are closed (or opened) the color of that week row become red (or green) , and if all days of month are closed (opened) the month label will becoe red (green) too. How do I use your pattern? – s1moner3d Apr 05 '16 at 15:23