Angular Change Detection and the OnPush Strategy


5

You have started using Angular for all of your favorite projects. You know what Angular has to offer, and how you can leverage it to build amazing web apps. But, there are certain things about Angular, and knowing they can make you better at using Angular for your projects.

Data flow being at the center of almost all things Angular, change detection is something worth knowing about, as it will help you trace bugs much more easily and give you an opportunity to further optimize your apps when working with a complex data set.

1

In this article, you will learn how Angular detects changes in its data structures and how you can make them immutable to make the most out of Angular’s change detection strategies.

Change Detection in Angular

When you change any of your models, Angular detects the changes and immediately updates the views. This is change detection in Angular. The purpose of this mechanism is to make sure the underlying views are always in sync with their corresponding models. This core feature of Angular is what makes the framework tick and is partly the reason why Angular is a neat choice for developing modern web apps.

A model in Angular can change as a result of any of the following scenarios:

  • DOM events (click, hover over, etc.)
  • AJAX requests
  • Timers (setTimer(), setInterval())

Change Detectors

All Angular apps are made up of a hierarchical tree of components. At runtime, Angular creates a separate change detector class for every component in the tree, which then eventually forms a hierarchy of change detectors similar to the hierarchy tree of components.

Whenever change detection is triggered, Angular walks down this tree of change detectors to determine if any of them have reported changes.

The change detection cycle is always performed once for every detected change and starts from the root change detector and goes all the way down in a sequential fashion. This sequential design choice is nice because it updates the model in a predictable way since we know component data can only come from its parent.

2

The change detectors provide a way to keep track of the component’s previous and current states as well as its structure in order to report changes to Angular.

If Angular gets the report from a change detector, it instructs the corresponding component to re-render and update the DOM accordingly.

Change Detection Strategies

Value vs. Reference Types

In order to understand what a change detection strategy is and why it works, we must first understand the difference between value types and reference types in JavaScript. If you are already familiar with how this works, you can skip this section.

To get started, let’s review value types and reference types and their classifications.

Value Types

  • Boolean
  • Null
  • Undefined
  • Number
  • String

For simplicity, one can imagine that these types simply store their value on the stack memory (which is technically not true but it’s sufficient for this article). See the stack memory and its values in the image below for example.

3

Reference Types

  • Arrays
  • Objects
  • Functions

These types are a bit more complicated as they store a reference on the stack memory, which points to their actual value on the heap memory. You can see how stack memory and heap memory work together in the example image below. We see the stack memory references the actual values of the reference type in the heap memory.

4

The important distinction to make between value types and reference types is that, in order to read the value of the value type, we just have to query the stack memory, but in order to read the value of a reference type, we need to first query the stack memory to get the reference and then secondly use that reference to query the heap memory to locate the value of the reference type.

Default Strategy

As we stated earlier, Angular monitors changes on the model in order to make sure it catches all of the changes. It will check for any differences between the previous state and current state of the overall application model.

The question that Angular asks in the default change detection strategy is: Has any value in the model changed? But for a reference type, we can implement strategies so that we can ask a better question. This is where OnPush change detection strategy comes in.

OnPush Strategy

The main idea behind the OnPush strategy manifests from the realization that if we treat reference types as immutable objects, we can detect if a value has changed much faster. When a reference type is immutable, this means every time it is updated, the reference on the stack memory will have to change. Now we can simply check: Has the reference (in the stack) of the reference type changed? If yes, only then check all the values (on the heap). Refer back to the previous stack heap diagrams if this is confusing.

The OnPush strategy basically asks two questions instead of one. Has the reference of the reference type changed? If yes, then have the values in heap memory changed?

For example, assume we have an immutable array with 30 elements and we want to know if there are any changes. We know that, in order for there to be any updates to the immutable array, the reference (on the stack) of it would have to have changed. This means we can initially check to see if the reference to the array is any different, which would potentially save us from doing 30 more checks (in the heap) to determine which element is different. This is called the OnPush strategy.

So, you might ask, what does it mean to treat reference types as immutable? It means we never set the property of a reference type, but instead reassign the value all together. See below:

Treating objects as mutable:

static mutable() {
  var before = {foo: "bar"};
  var current = before;
  current.foo = "hello";
  console.log(before === current);
  // => true
}

Treating objects as immutable:

static mutable() {
  var before = {foo: "bar"};
  var current = before;
  current = {foo "hello"};
  console.log(before === current);
  // => false
}

Note that, in the examples above, we are “treating” reference types as immutable by convention, so in the end we are still working with mutable objects, but just “pretending” they are immutable.

So how do you implement OnPush strategy for a component? All you need to do is add the changeDetectionparameter in their @Component annotation.

import {ChangeDetectionStrategy, Component} from '@angular/core';

@Component({
  // ...
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnPushComponent {
  // ...
}

Immutable.js

It is a good idea to enforce immutability if one decides to use the OnPush strategy on an Angular component. That is where Immutable.js comes in.

Immutable.js is a library created by Facebook for immutability in JavaScript. They have many immutable data structures, like List, Map, and Stack. For the purposes of this article, List and Map will be illustrated. For more reference, please check out the official documentation here.

In order to add Immutable.js to your projects, please make sure to go into your terminal and run:

$ npm install immutable --save

Also make sure to import the data structures you are using from Immutable.js in the component where you are using it.

import {Map, List} from 'immutable';

This is how an Immutable.js Map can be used:

var foobar = {foo: "bar"};
var immutableFoobar = Map(foobar);

console.log(immutableFooter.get("foo"));
// => bar

And, an Array can be used:

var helloWorld = ["Hello", "World!"];
var immutableHelloWorld = List(helloWorld);
console.log(immutableHelloWorld.first());
// => Hello
console.log(immutableHelloWorld.last());
// => World!

helloWorld.push("Hello Mars!");
console.log(immutableHelloWorld.last());
// => Hello Mars!

Drawbacks of Using Immutable.js

There are a couple main arguable drawbacks of using Immutable.js.

As you may have noticed, it’s a bit cumbersome to use its API, and a traditional JavaScript developer may not like this. A more serious problem has to do with not being able to implement interfaces for your data model since Immutable.js doesn’t support interfaces.

Wrap Up

You may be asking why the OnPush strategy is not the default strategy for Angular. I presume it is because Angular didn’t want to force JavaScript developers to work with immutable objects. But, that doesn’t mean you are forbidden from using it.

If that is something you want to leverage in your next web project, you now know how easy Angular makes it to switch to a different change detection strategy.

Feel free to share on social networks. Find the buttons below this post. This opinion article is for informational purposes only.

Remember, information/knowledge is never enough. Let us spread the word!

Follow my blog for more insightful articles: http://temitopeadelekan.com

LinkedIn connect: Temitope Adelekan

Twitter: @taymethorpenj

 

 

 

This is article is written by  Ahmet Shapiro-Erciyas

Brought to you by Toptal

Edited by Temitope Adelekan


					
Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s