Change detection stands as a core mechanism in Angular, tasked with detecting and applying modifications to the DOM whenever underlying data shifts or user interactions occur. This procedure keeps the user interface in sync with the application state, boosting both performance and the overall user experience.

The Role of Zone.js

Traditionally, Angular's change detection has been built on Zone.js. This JavaScript library intercepts asynchronous operations, enabling Angular to track changes and initiate update cycles automatically. The downside, however, is that Zone.js introduces additional overhead, which can become noticeable in apps with heavy asynchronous activity.

Change Detection Strategies

Angular offers two main strategies for change detection:

  • Default: Here, change detection runs after every lifecycle hook, such as ngOnInit or ngAfterViewInit. This method is simple, but it can cause redundant DOM updates, particularly in larger applications.
@Component({
  selector: 'app-my-component',
  template: `
    <p>{{ message }}</p>
  `
})
export class MyComponent {
  message = 'Hello, world!';
}

Enter fullscreen mode Exit fullscreen mode

This strategy is simpler to adopt, as Angular handles most of the detection logic without requiring direct intervention.
Its primary drawback was that it often produced avoidable DOM updates, a concern that becomes critical in sizable applications.

  • OnPush: In this approach, change detection activates only when input properties or asynchronous observables emit changes. This strategy offers better performance for complex components that undergo frequent data updates, though it demands more hands-on management.
@Component({
  selector: 'app-my-component',
  template: `
    <p>{{ message }}</p>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
  message = 'Hello, world!';
} 

Enter fullscreen mode Exit fullscreen mode

Although onPush cut down on unnecessary DOM modifications, it introduced its own obstacles. Developers found themselves handling more manual tasks, needing to invoke change detection explicitly via changeDetectorRef.detectChanges() in situations like indirect data updates or when working with mutable objects.

Angular 18 and Hybrid Change Detection: A Zone-less Approach

To overcome the issues tied to Zone.js, Angular 18 unveiled an experimental feature called Hybrid Change Detection. This strategy seeks to completely do away with Zone.js, relying instead on a fresh detection mechanism to spot changes and update the DOM.

Enabling Hybrid Change Detection:

Activating Hybrid Change Detection is done with the following code snippet:

bootstrapApplication(RootCmp,
{ providers: [provideExperimentalZonelessChangeDetection()] 
}
);

Enter fullscreen mode Exit fullscreen mode

With this setup, change detection will be triggered under these conditions:

  • A signal gets updated.
  • changeDetectorRef.markForCheck() is invoked.
  • An observable bound via the AsyncPipe delivers a new value.
  • A component is attached or detached from the view tree.
  • An input binding receives a new value.

After enabling Hybrid Change Detection, you have the option to drop Zone.js from your application's polyfills.

 "polyfills": [
              "zone.js" //remove this line
            ],
Enter fullscreen mode Exit fullscreen mode

Benefits of Hybrid Change Detection

  • Improved performance: Doing away with Zone.js cuts down on overhead, which enhances performance, especially in apps with a high volume of asynchronous tasks.

  • Enhanced developer experience: Eliminating manual change detection streamlines development and lowers the chance of introducing bugs.

  • Smaller application size: Zone.js adds roughly 13KB to the bundle size. Removing it can result in a more compact build.