$watch and performance

AngularJS is great for developers.  Works like magic – you just state {{varName}}, fill it up with some data, and it just appears on screen.  What really happens behind the scenes is that angular sets a $watch for every {{}} expression.

Let’s take a small example of a menu:

You can go to the example and change the menu texts using the input fields to see the magical binding in action.

In this example, for every menu item, 5 watchers are being called for every digest – url, text, icon, style and input field.  A digest would run for EVERY socket call in addition to any user interaction (i.e. button click). This is fine when we have a 5 items menu. What happens when we create a 100 items menu? Or maybe more?

Since BIKS handles a lot of real-time data processing, it is very important to note this important performance trap.  It’s very easy to set these watchers and watch the magic works – only to collapse when the real-time data starts pouring from the server after the integration.

There are many methods to handle this, and each of them depends on the context of the issue. One such context is the binding of constants.

Let’s assume the the icon and the text aren’t going to change.  By utilizing angular’s bindonce feature, we can drop two listeners:

In the example above, try to change the text in the menu input fields.  Nothing happens… this is because I’ve used bindOnce.  The “trick” is to add “::” before the bound property (i.e. {{::item.text}}). Notice that I did the same for the icon.  This removed 2 watchers. If I had a 100 items in my list, it would have saved me 200 watchers – for every digest cycle… a huge performance boost for the app.

There are many more ways to remove watchers from your app, and method usually depends on the context.  The bindOnce method is the simplest and most straight forward for constants binding.

Experienced other contexts that required $watch removal? Found more methods? Please share in the comments or write a post about it.

Leave a Reply