Saturday, February 8, 2014

Instrumenting Angular with Zone

In my last post I described an open source tool from the Angular team called Zone that allows you to execute a JavaScript workflow within an execution context. I demonstrated how to instrument a sequence of asynchronous events using Zone. This is a short post to follow-up and illustrate how to do the same thing in Angular.

The first step, of course, is to Angular-ize the HTML. This is simple enough. Instead of manually binding a click function, I can use the ng-click directive, and instead of manually setting the data I can use data-binding.

<div>
    <button id="myBtn" ng-click="populate()">Populate</button>
    <span id="myData">{{data}}</span>
</div>


In order to put Angular “into the Zone” we need to capture the bootstrap process. By default Angular will run and find directives to bind to, but we want to defer this step so that it runs in the context of a zone. To keep the example simple I’m not using a controller and will just set everything up on the $rootScope.

var main = function() {
    zone.marker = "main";
    console.log('getting injector');
    angular.module('myApp', []).run(function($rootScope, $timeout){
        zone.marker = "module run";
        $rootScope.populate = function() {
            zone.marker = "click";
            $rootScope.data = "Initializing...";
            $timeout(function() {
                zone.marker = "timeout";
                $rootScope.data = "Done";
            }, 2000);
        };
    });
    angular.bootstrap(document, ['myApp']);
};


That’s really it. This should look very similar to the previous example. Note that besides the zone “markers” I set up to make the console output more readable, there is nothing that changes in the Angular code itself – everything is handled by virtue of it being run from within a zone. The zone is fired up the same way as the previous example:

zone.fork(profilingZone).run(function() {
    zone.reset();
    main();
});


When it’s run you can see we get a sequential profile of the asynchronous events … for example, notice the time elapsed between the last two is almost exactly 2 seconds or the interval that I set using Angular’s $timeout service.

Entered task
Exited task module run after 22.999999986495823
Total active time: 22.999999986495823
Total elapsed time: 22.999999986495823
Entered task
Exited task click after 3.9999999571591616
Total active time: 26.999999943654984
Total elapsed time: 4333.999999973457
Entered task
Exited task timeout after 0.9999999892897904
Total active time: 27.999999932944775
Total elapsed time: 6333.999999973457

The full fiddle for this example is here. I included the Zone source because I’m not aware of a CDN for it yet.