Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count total number of watches on a page?

Tags:

angularjs

People also ask

How many watches an angular page can have at max?

You can have as many watchers as you want. There is no finite numbers of watchers, if you register 1000 watchers those will all work, if you register 10000 watchers, they will still all work.

How do I count the number of watchers in Angularjs?

you can get the number $watch() bindings on any AngularJS application. — Anything over 2,000 is considered bad for performance.

What is watchers in AngularJS?

watchers is nothing but dirty checking, which keeps a track of the old value and new value. They are getting evaluated on each digest cycle. It can be combination of scope variable or any expression. Angular does collect all of this watchers on each digest cycle and mainatain it inside $$watchers array.


(You may need to change body to html or wherever you put your ng-app)

(function () { 
    var root = angular.element(document.getElementsByTagName('body'));

    var watchers = [];

    var f = function (element) {
        angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) { 
            if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
                angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) {
                    watchers.push(watcher);
                });
            }
        });

        angular.forEach(element.children(), function (childElement) {
            f(angular.element(childElement));
        });
    };

    f(root);

    // Remove duplicate watchers
    var watchersWithoutDuplicates = [];
    angular.forEach(watchers, function(item) {
        if(watchersWithoutDuplicates.indexOf(item) < 0) {
             watchersWithoutDuplicates.push(item);
        }
    });

    console.log(watchersWithoutDuplicates.length);
})();
  • Thanks to erilem for pointing out this answer was missing the $isolateScope searching and the watchers potentially being duplicated in his/her answer/comment.

  • Thanks to Ben2307 for pointing out that the 'body' may need to be changed.


Original

I did the same thing except I checked the data attribute of the HTML element rather than its class. I ran yours here:

http://fluid.ie/

And got 83. I ran mine and got 121.

(function () { 
    var root = $(document.getElementsByTagName('body'));
    var watchers = [];

    var f = function (element) {
        if (element.data().hasOwnProperty('$scope')) {
            angular.forEach(element.data().$scope.$$watchers, function (watcher) {
                watchers.push(watcher);
            });
        }

        angular.forEach(element.children(), function (childElement) {
            f($(childElement));
        });
    };

    f(root);

    console.log(watchers.length);
})();

I also put this in mine:

for (var i = 0; i < watchers.length; i++) {
    for (var j = 0; j < watchers.length; j++) {
        if (i !== j && watchers[i] === watchers[j]) {
            console.log('here');
        }
    }
}

And nothing printed out, so I'm guessing that mine is better (in that it found more watches) - but I lack intimate angular knowledge to know for sure that mine isn't a proper subset of the solution set.


I think the mentioned approaches are inaccurate since they count watchers in the same scope double. Here is my version of a bookmarklet:

https://gist.github.com/DTFagus/3966db108a578f2eb00d

It also shows some more details for analyzing watchers.


Here is a hacky solution that I put together based on inspecting the scope structures. It "seems" to work. I'm not sure how accurate this is and it definitely depends on some internal API. I'm using angularjs 1.0.5.

    $rootScope.countWatchers = function () {
        var q = [$rootScope], watchers = 0, scope;
        while (q.length > 0) {
            scope = q.pop();
            if (scope.$$watchers) {
                watchers += scope.$$watchers.length;
            }
            if (scope.$$childHead) {
                q.push(scope.$$childHead);
            }
            if (scope.$$nextSibling) {
                q.push(scope.$$nextSibling);
            }
        }
        window.console.log(watchers);
    };

There is a new chrome plugin that automatically shows the current total watchers and the last change (+/-) at any time in your app... it's pure awesome.

https://chrome.google.com/webstore/detail/angular-watchers/nlmjblobloedpmkmmckeehnbfalnjnjk


Minor improvement for Words Like Jared's answer.

(function () {
    var root = $(document.getElementsByTagName('body'));
    var watchers = 0;

    var f = function (element) {
        if (element.data().hasOwnProperty('$scope')) {
            watchers += (element.data().$scope.$$watchers || []).length;
        }

        angular.forEach(element.children(), function (childElement) {
            f($(childElement));
        });
    };

    f(root);

    return watchers;
})();