Let’s Write Faster AngularJS App
AngularJS is the most popular JavaScript framework as of now - it’s being used for creating websites, and mobile apps (Ionic Framework).
Let’s be honest, even with it’s crazy popularity, it’s not as fast as it should be. Yes, it’s improving. So we want to write faster AngualarJS code, here are a few small tips on making your code faster, and more memory efficient.
1. Use Bind once when possible
A new feature landing in AngularJS 1.3 is the ability to bind an expression to a view without adding a watcher and constantly digesting it. A clever nuance of the feature is the fact that while an expression is undefined the watcher will remain. Once the expression is defined however the watcher will be removed.
Bind once aims to go some of the way towards alleviating this by allowing you to decrease the number of expressions being watched, making the digest loop faster and your application more performant.
The syntax is simple, just prepend an expression with ::
. Here’s some examples.
<div>{{ ::item }}</div>
You could also use bind once within the ng-repeat
rather than when defining it to only bind once specific expressions.
<ul>
<li ng-repeat="item in ::items">{{ item }}</li>
</ul>
If you are on pre 1.3 version of Angular, you can use this library bindonce
2. Debouncing Your ng-model Updates
One of the biggest bottlenecks in Angular 1.x is the $digest
cycle. For example if you have a text field using an ng-model
, whenever you type in a value into this field, it will trigger a $digest
cycle causing Angular to update all watchers and bindings in the app to see if anything has changed.
In version 1.3 of Angular, a native debounce feature was introduced which can be supplied to ngModelOptions
.
Debouncing is a delay which says, “Wait X amount of time and then do this action if an action is not already in progress” so in the instance of waiting for typing in a field for an email for example, you might want to put in a delay of 300 milliseconds so if a user stops typing and doesn’t resume within 300 milliseconds, an action will be fired which will trigger a $digest
cycle.
<input type="text" name="userName" ng-model="user.name" ng-model-options="{ debounce: 300 }" />
By using debounce on your input fields and anywhere else where an instant update is not required, you can increase the performance of your Angular apps quite substantially
3. Use ng-if instead of ng-show
The ng-if
removes or recreates a portion of the DOM tree based on an expression. If the expression assigned to ng-if
evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
<!-- when $scope.myValue is truthy (element is restored) -->
<div ng-if="1"></div>
<!-- when $scope.myValue is falsy (element is removed) -->
<div ng-if="0"></div>
When an element is removed using ng-if
its scope is destroyed and a new scope is created when the element is restored. The scope created within ng-if
inherits from its parent scope using prototypal inheritance.
The ng-show
directive shows or hides the given HTML element based on the expression provided to the ng-show
attribute. ng-show
will render an element, and use display:none
to hide it.
When you want to toggle the portion of your page, ng-if
is a better way to go.
4. Avoid ng-repeat where possible
It is better to avoid ng-repeat where we can and where it makes sense.The ng-repeat
directive is most likely the worst offender for performance concerns, which means it can easily be abused. An ng-repeat likely deals with Arrays of $scope
Objects and this hammers the $digest
cycle’s performance.
If at all possible, avoid long lists. ng-repeat
does some pretty heavy DOM manipulation (not to mention polluting $$watchers), so try and keep any lists of rendered data small whether through pagination or infinite scroll.
You can read this article Solution to the ng-repeat performance problem
5. Avoid using filters if at all possible
They are run twice per digest cycle, once when anything changes, and another time to collect further changes, and do not actually remove any part of the collection from memory, instead simply masking filtered items with css.
This renders $index
worthless as it no longer corresponds to the actual array index, but the sorted array index. It also prevents you from letting go of all of the list’s scopes
You can avoid the inline filter syntax as below.
{{ myArray | myFilter }}
Angular includes a $filter
provider, which you can use to run filters in your JavaScript before parsing into the DOM. This will preprocess our data before sending it to the View, which avoids the step of parsing the DOM and understanding the inline filter syntax.
var myFilter = $filter('myFilter');
$scope.filteredArray = myFilter(myArray);
6. Use Batarang to debug
AngularJS Batarang is a powerful Chrome extension that makes your developer tools “Angular aware”. It helps in debugging and profiling AngularJS applications.
You can download AngularJS Batarang chrome extension from here
If you found these tips helpful, recommend and share so others can learn about these tips too! Let’s make the community build faster AngularJS apps.
If you have any other tips, share it in comments.
Want to track angularjs exceptions and measure performance? Learn more about Atatus