Angular变更检测机制
- 何时触发:
- 事件触发:当用户与页面进行交互,如点击按钮、输入文本等DOM事件发生时,Angular的变更检测机制会被触发。
- Promise或Observable异步操作完成时:当Promise被resolved或rejected,或者Observable发出新的值时,变更检测也会启动。例如,通过
HttpClient
发起HTTP请求获取数据后,响应数据返回时会触发变更检测。
- setTimeout和setInterval:使用JavaScript原生的
setTimeout
和setInterval
时,当回调函数执行,也会触发变更检测。
- 如何检测变化:
- 脏检查机制:Angular使用脏检查机制来检测变化。它从根组件开始,遍历组件树,检查每个组件的输入属性(
@Input()
)和绑定的属性(如[ngModel]
等)。对于每个组件,它会比较当前值和上一次检查的值。如果发现有任何值发生了变化,就认为该组件“脏了”,需要更新视图。
- 检查顺序:先检查组件的输入属性,然后检查模板表达式,包括插值(
{{}}
)、属性绑定([attr]
)、事件绑定((event)
)等。
大型应用中提高变更检测性能的优化策略
- 利用OnPush策略:
- 原理:将组件标记为
ChangeDetectionStrategy.OnPush
时,Angular会优化该组件的变更检测。只有在以下情况下,该组件及其子组件才会触发变更检测:
- 组件接收到新的输入值(引用变化)。例如,如果输入是一个对象,当对象的引用改变时(而不是对象内部属性改变),才会触发变更检测。
- 组件触发了一个事件,如按钮点击事件。
- 从Observable中接收到新的值,前提是该Observable是使用
observeOn
调度到Angular的NgZone
(默认情况下,HttpClient
返回的Observable满足此条件)。
- 使用方法:在组件的
@Component
装饰器中设置changeDetection: ChangeDetectionStrategy.OnPush
。例如:
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app - my - component',
templateUrl: './my - component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {}
- 不可变数据结构:
- 原理:使用不可变数据结构可以减少不必要的变更检测。因为当数据是不可变的,每次数据变化都会创建一个新的对象或数组,而不是修改原有对象。这使得Angular可以通过简单的引用比较(
===
)来判断数据是否发生了变化。如果引用没有改变,Angular就认为数据没有变化,不会触发不必要的变更检测。
- 使用方法:在JavaScript中,可以使用
Object.freeze
创建不可变对象,或者使用像immer
这样的库来更方便地处理不可变数据。例如,使用immer
更新数组:
import produce from 'immer';
const initialArray = [1, 2, 3];
const newArray = produce(initialArray, draft => {
draft.push(4);
});
- 在组件中使用不可变数据时,确保将新的不可变数据赋值给输入属性,而不是直接修改原有数据。这样可以利用OnPush策略和引用比较来优化变更检测。