ng-stats | Utility to show stats about angular digest/watches.

ng-stats angular directive

ng-stats

Stars : 10

Forks : 10

Created by Kent C. Dodds

bower install ng-stats

Demo Download GitHub

ng-stats

unmaintained

npm version npm downloads Build Status Code Coverage Gitter

Little utility to show stats about your page's angular digest/watches. This library currently has a simple script to produce a chart (see below). It also creates a module called angularStats which has a directive called angular-stats which can be used to put angular stats on a specific place on the page that you specify.

Sponsor

Example Green (digests are running smoothly):

Example Green

Example Red (digests are taking a bit...):

Example Red

Interactive Demo

The first number is the number of watchers on the page (including {{variables}}, $scope.$watch, etc.). The second number is how long (in milliseconds) it takes angular to go through each digest cycle on average (bigger is worse). The graph shows a trend of the digest cycle average time.

Thanks

Viper Bailey for writing the initial version (and most of the graph stuff).

Development

  1. npm install
  2. bower install
  3. grunt for server
  4. grunt release for release

Installation

Bookmarklet

Copy the code below and create a bookmarklet for ng-stats to use it on any angular website (so long as the debug info is enabled, if not, you'll need to run angular.reloadWithDebugInfo() first).

javascript: (function() {var a = document.createElement("script");a.src = "https://rawgit.com/kentcdodds/ng-stats/master/dist/ng-stats.js";a.onload=function(){window.showAngularStats()};document.head.appendChild(a)})();

If you just want the chart for development purposes, it's actually easiest to use as a Chrome DevTools Snippet. Just copy/paste the dist/ng-stats.js file into a snippet.

However, it uses UMD, so you can also include it in your app if you want via:

$ npm|bower install ng-stats

or download dist/ng-stats.js and

<script src="path-to/ng-stats.js"></script>

or

var showAngularStats = require('path-to-ng-stats');

You now have a angularStats module and showAngularStats function you can call

Chart

Usage

Simply invoke showAngularStats( { options } ) and the chart will appear. It also returns an object with a few handy things depending on your options. One of these things is listeners which is an object that has two objects: digestLength and watchCount. You can add a custom listener that is called when the digest cycles happen (though for performance reasons when calculating the watchCount, the watchCount listeners are throttled). Here's an example of adding custom listeners:

var ngStats = showAngularStats();

ngStats.listeners.digestLength.nameOfYourListener = function(digestLength) {
  console.log('Digest: ' + digestLength);
};

ngStats.listeners.watchCount.nameOfYourListener = function(watchCount) {
  console.log('Watches: ' + watchCount);
};

Options

You can pass the function one (optional) argument. If you pass false it will turn off "autoload" and do nothing. You can also pass an object with other options:

position (object) - default: 'topleft'

Controls the position of the graphic. Possible values: Any combination of top, left, right, bottom.

digestTimeThreshold (number) - default: 16

The time (in milliseconds) where it goes from red to green.

autoload (string or boolean) - default: false

Uses the Storage API to store whether the graphic should be automatically loaded every time the page is reloaded. Pass in 'localStorage' for persistent loading or 'sessionStorage' to load ng-stats for only the current session.

Note, if you pass false as options, it will simply remove the stats window and exit: showAngularStats(false)

trackDigest (boolean) - default: false

showAngularStats returns an object. Setting this to true will add an array to that object called digest that holds all of the digest lengths.

trackWatches (boolean) - default: false

showAngularStats returns an object. Setting this to true will add an array to that object called watches that holds all of the watch counts as they change.

logDigest (boolean) - default: false

Setting this to true will cause ng-stats to log out the digest lengths to the console. It will be colored green or red based on the digestTimeThreshold.

logWatches (boolean) - default: false

Setting this to true will cause ng-stats to log out the watch count to the console as it changes.

htmlId (string) - default: null

Sets an HTML ID attribute to the rendered stats element.

rootScope (object) - default: undefined

Passes the $rootScope to ng-stats. This parameter is only required for Ionic support where the ng-scope and ng-isolate-scope classes are removed. The only way of using the ng-stats with Ionic is invoking showAngularStats( { options } ) in your code and passing the $rootScope manually.

Module

Simply declare it as a dependency angular.module('your-mod', ['angularStats']);

Then use the directive:

<div angular-stats watch-count=".watch-count" digest-length=".digest-length"
     on-watch-count-update="onWatchCountUpdate(watchCount)"
     on-digest-length-update="onDigestLengthUpdate(digestLength)">
  Watch Count: <span class="watch-count"></span><br />
  Digest Cycle Length: <span class="digest-length"></span>
</div>

angular-stats attributes

angular-stats

The directive itself. No value is expected

watch-count

Having this attribute will keep track of the watch count and update the text of a specified element. Possible values are:

  1. Selector for a child element to update
  2. no value - refers to the current element (updates the text of the current element)

watch-count-root

angular-stats defaults to keeping track of the watch count for the whole page, however if you want to keep track of a specific element (and its children), provide this with a element query selector. As a convenience, if this is provided then the watch-count-root will be set to the element itself. Also, if you want to scope the query selector to the element, add watch-count-of-child as an attribute (no value)

on-watch-count-update

Because of the performance implications of calculating the watch count, this is not called every digest but a maximum of once every 300ms. Still avoid invoking another digest here though. The name of the variable passed is watchCount (like you see in the example).

digest-length

This works similar to the watch-count attribute. It's presence will cause the directive to keep track of the digest-length and will update the text of a specified element (rounds to two decimal places). Possible values are:

  1. Selector for a child element to update
  2. no value - refers to the current element (updates the text of the current element)

on-digest-length-update

Pass an expression to evaluate with every digest length update. This gets called on every digest (so be sure you don't invoke another digest in this handler or you'll get an infinite loop of doom). The name of the variable passed is digestLength (as in the example).

Roadmap

  • Add analysis to highlight areas on the page that have highest watch counts.
  • Somehow find out which watches are taking the longest... Ideas on implementation are welcome...
  • See what could be done with the new scoped digest coming in Angular version 1.3.
  • Count the number of digests or provide some analytics for frequency?
  • Create a Chrome Extension for the chart or integrate with batarang?
  • Other ideas?

Other notes

Performance impact

This will not impact the speed of your application at all until you actually use it. It also will hopefully only negatively impact your app's performance minimally. This is intended to be used in development only for debugging purposes so it shouldn't matter much anyway. It should be noted that calculating the watch count can be pretty expensive, so it's throttled to be calculated a minimum of 300ms.

Using in an iframe

Thanks to this brilliant PR from @jinyangzhen, you can run ng-stats in an iframe (like plunker!). See the PR for an example of how to accomplish this.

License

MIT

Javscript

Javascript plugin

Angular-js