In-Depth Look at Angular's Change Detection, Mode Switching and DOM Traversal
Overview
In this document, we will build upon our previous discussion of Angular's change detection system, which helps synchronize the UI with the app's internal state. By referring to the concepts outlined in the last documentation, we can gain a complete understanding of how Angular detects changes and updates the DOM.
Recap of Previous Documentation
In the previous document, we covered:
Expanding on Change Detection Algorithms
In this documentation, we will dive deeper into how Angular marks a component as dirty and how it uses Global and Targeted change detection algorithms to optimize the process of updating the DOM.
Marking a Component as Dirty
Angular identifies when part of the UI needs to be synchronized with the DOM by marking the component as dirty. There are three ways Angular determines a component’s dirtiness:
By doing this, Angular now knows the application’s dirtiness state and what operations need to happen at the application level (e.g., effects, rendering, and after-render hooks). This allows for fine-grained control over what needs to be updated in the UI.
Here’s a simplified version of how Angular performs the change detection check at the top level:
while(dirty) {
if (dirty & Dirty.RootEffects) runRootEffects();
if (dirty & Dirty.Views) checkViews();
// If there are still dirty views, loop back
if (dirty & Dirty.Views) continue;
if (dirty & Dirty.RenderHooks) runRenderHooks();
}
This loop ensures that change detection is performed as long as there are dirty components or operations. The traversal occurs in cycles, ensuring no part of the tree is missed, and it handles cases where lifecycle hooks or signals might mark additional components as dirty.
How Do We Check Views?
Angular checks views using two modes: Global Mode and Targeted Mode.
These two modes allow Angular to prune parts of the component tree that do not require change detection, improving performance by skipping checks on components that cannot have updates.
Following this approache change detection will scale based on the number of changes, not the size of the application.
Global Mode vs. Targeted Mode (Mode Switching)
Angular optimizes change detection by switching between Global Mode (Default Strategy) and Targeted Mode (OnPush Strategy) as needed during the traversal of the component tree. This ensures that only relevant components are checked, and the application remains performant, especially in large apps.
The modes switch during traversal:
领英推荐
As Angular traverses from parent to child, it switches between these modes based on the conditions:
This mode switching mechanism allows Angular to minimize unnecessary checks and improve performance by limiting the number of components visited during change detection.
Mode Switching in Practice: Examples
Example 1: Global Mode to Targeted Mode
Consider an application where you have a parent component and a child component. The parent component is set to use the Default Change Detection Strategy (which is Global Mode), and the child component is set to use the OnPush Change Detection Strategy (which is Targeted Mode).
Scenario:
Thus, when Angular encounters the parent in Global Mode, it switches to Targeted Mode for the child. This allows the child component to be checked only if necessary (i.e. if it is dirty or marked for check).
Flow:
Example 2: Targeted Mode to Global Mode
Let’s consider another example where we have a parent component using the OnPush Change Detection Strategy (Targeted Mode) and a child component using the Default Strategy (Global Mode).
Scenario:
Let’s say the parent component's state triggers a signal, which makes the child component’s state dirty. Angular, upon encountering the child, switches to Global Mode to check the child component (because the child component is using the Default Strategy).
Flow:
Conclusion
Angular’s change detection system uses a combination of Global Mode and Targeted Mode to optimize the performance of UI updates. The key to this optimization lies in the mode-switching mechanism, which ensures that only the necessary components are checked, thus minimizing the computational overhead during change detection. The flexibility to switch between these modes based on component strategies (OnPush vs Default) allows Angular to handle large and complex applications efficiently.
By understanding how dirty components are tracked and how mode switching occurs, developers can leverage Angular’s change detection system to build performant, scalable applications that are both responsive and efficient.
Amazing insight! Thank you for sharing