Angular Performance improvement using change detection — Default and OnPush

Tushar Ghosh
5 min readMay 31, 2021
Angular change detection

Change detection is responsible to update the view (DOM) data when state data has changed. By default, when a state value in component is changed, Angular updates all child component to sync the value between view and component for all time. We can take some strategy to avoid the unnecessary component update that will improve the Angular application performance. Most of the time (around 80–90% of projects), you don’t need to work with change detection, but if you work with large Angular application or handle with large data that’s time some change detection strategy make the application robust and fast. In this article, I will try to cover this strategy to improve the Angular performance.

How change detection works:

ngZone is responsible to run the asynchronous code and also automatically inform the Angular to run the change detection operation based on events (Click, Timer, HTTP call) . We are not going to deep about ngZone.

Types of change detection strategy?

By default, Angular updates the each component from top to bottom when any event like browser event, API call, or timer happened in any component. If we can reduce the the number of checking, then we are able to reduce the run change detection update for sub component. There are two type strategy for change detection:

  1. Default strategy
  2. OnPush strategy

Default strategy:

By default, Angular uses this strategy ChangeDetectionStrategy.Default to render view of a component. It will update all component view from top to bottom, whenever an event is triggered( eg. XHR, promise, user events) of any component. This unnecessary change detection checking leads to performance issue when you are working with large project or handling large data.

Here NG code 1, after clicking the “Change title” button, title is changing for the change detection of ParentComponent. At the same time, change detection of ChildComponent and GrandChildComponent update the view render whereas there is no state change (see Output-1).

NG code 1: Change detection default
Outpout-1: Change detection default

When default change detection is called:

  1. Any event (Click, Key-up, Change event, etc)
  2. HTTP request for API
  3. Timers (setInterval(), setTimeout())

OnPush strategy

OnPush strategy will not check the unnecessary dirty checking in ChildComponent and it’s child component ,GrandChildComponent, after applying the ChangeDetectionStrategy.onPush strategy. It will make the component faster. (See NG code 2 and Output 2).

Here, we can see that, title state of ChildComponent is not updating due to “changeDetection: ChangeDetectionStrategy.OnPush”. We can change the state manually by running the change detector to update the view. Angular provides markForCheck method that instruct Angular to check the component as the next time change detectors run. We will discuss later in below sections.

NG code 2: Change detection OnPush
Output 2: Change detection of OnPush.

ChangeDetectionStrategy.OnPush change detection in your component would be run when

  • A primitive or reference of an @Input() value has changed
  • An event is received (click, keyup)
  • | async pipe received an event
  • Change detection is invoked “manually

OnPush and the mutability trap ( An "@Input() value has changed" )

In the NG code 3, we can see user object is sending as a “@Input” properties. When application is initialize that time it is showing the the user name. But after clicking the “Change user name” button, user name in object is changing in ParentComponent, but this changes is not effecting the ChildComponent. Because the user object is mutated from the parent element, the reference is not updated in the Child Component, so @Input Component is not receiving a new reference and will not be updated since the Objects in @Input property as still same reference.

NG code 3: OnPush and the mutability trap

So, we should create a new object with updated properties so that the reference of @Input property updates and the ChildComponent is notified about the Component Update. Change the code of changeName() method like as NG code 4, then it we can see the changed user name in ChildComponent.

NG code 4: OnPush and the mutability trap

An event is received in OnPush component:

OnPush component invokes the change detection when any browser event triggered on those component. So, “NG code 3" just replaced by “NG code 5” in ChildComponent. Now the ChildComponent has a Refresh button. A click on the Refresh button would instruct Angular to run the change detector, and, as a result of that, the view will be updated with the latest value of the user.

NG code 5: OnPush and an event trigger

OnPush, Observables and the async pipe ( Async pipe received an event):

By using the async pipe, we don’t have to manually call the change detector, subscribe to the observable, and unsubscribe to the observable because the async pipe does all these tasks. See the NG code 6 .

The async pipe is a cleaner approach, and it is recommended to use it while working with observable data and onPush change detection strategy.

NG code 6: Async pipe

Change detection is invoked “manually”:

We can mark a view as dirty using the ChangeDetectionRef abstract class methods. Use the methods to add and remove views from the CD tree, initiate change-detection, and explicitly mark views as dirty, meaning that they have changed and need to be re-rendered. The methods are

  • markForCheck()
  • detach()
  • detectChanges()
  • reattach()

markForCheck():

In the OnPush strategy, we can use markForCheck() method to mark the view as dirty for re-rendering the view by Change Detection.

detach() and detectChanges():

These two methods are used together. detach() is used to detach the view component from the Change Detection tree, and detectChanges() is used to call when you want the change detection to run. The detectChanges method runs the change detector for the current component and its children.

reattach():

reattach the previously detached view to the change detection tree.

References:

--

--

Tushar Ghosh

MEAN | JavaScript | Node.js | React| Angular | Frontend