AngularJs, Javascript, Optimizations, Performance

Shorten $digest cycles with one time bindings


In large scale angular apps (or poorly designed small-medium scale), performance issues, if not caught on time, could be extremely painful to fix. Memory leaks, uncontrolled watchers, unnecessary expressions processed during the $digest cycle and the list goes on and on.

Today I wanted to share a little addition presented in angular 1.3 and allows us to shorten our $digest cycles.

Consider the following (simple) example:

Controller


myController.controller('MyController', function($scope, urlConfigurations, $timeout) {
    var vm = this;
    vm.userId = 'firstUser';
    vm.facebookProfile = urlConfigurations.facebook;
    vm.twitterProfile = urlConfigurations.twitter;
    vm.linkedin = urlConfigurations.linkedin;

    vm.nextUser = function() {
        vm.userId = 'secondUser';
    };
});

Constant

myApp.constant('urlConfigurations', {
    	facebook: 'http://facebook.com/?profile=',
        twitter: 'http://www.twitter.com/?id=',
        linkedin: 'http://www.linkedin.com/?id='
});

View

<div ng-controller="MyController as vm">
      <a ng-href="{{vm.facebookProfile + vm.userId}}">Facebook</a>
      <a ng-href="{{vm.twitterProfile + vm.userId }}">Twitter</a>
      <a ng-href="{{vm.linkedin + vm.userId}}">Linkedin</a>
      
      <button ng-click="vm.nextUser();">Next User</button>
</div>

Looks legitimate piece of code, right? We have urlConfigurations constant which holds our URLs, then we retrieve it in our controller and sending it to the view , which combining it with vm.userId to create links to social media account of the specific user id. The nextUser() method allows us to change the user id, which will also modify the social media URLs.

Where is the problem?

The problem is that we have 3 unnecessary watchers here: vm.facebookProfile, vm.twitterProfile and vm.linkedin. So, when we will update vm.userId, it will trigger a $digest cycle that will process everything on the scope, including those 3 watchers that will never change in runtime, making processing them redundant and time/resources consuming. Now consider a case where we don’t have only 3, maybe we have a 100 (a good example might be localization implementation).

The solution

As for angular 1.3 > , the solution is quite simple. We can just add :: near the property we want to bind only once. So in our view, we will be using:

<a ng-href="{{::vm.facebookProfile}}{{vm.userId}}">Facebook</a>
<a ng-href="{{::vm.twitterProfile}}{{vm.userId}}">Twitter</a>
<a ng-href="{{::vm.linkedin}}{{vm.userId}}">Linkedin</a>

In this case, vm.facebookProfile, vm.twitterProfile and vm.linkedin won’t be processed in the $digest cycle each time vm.userId is modified.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s