Angular变更检测

1 变更检测

1.1 变更检测的概念

负责检测Angular组件中数据的变化,实时地更新视图。

1.2 变更检测的触发时机

Angular会在发生异步操作(这些操作常常会引起数据改变)后,触发变更检测,实时地更新视图。

常见的异步操作有以下几种

  • HTTP请求:通过Ajax请求或Fetch API 发送HTTP请求在后台获取数据
  • 定时器任务:setTimeout/setInterval
  • 事件处理:用户交互事件(点击、滚动、键盘输入等)
  • 自定义的异步函数

1.3 变更检测是如何工作的(待补充)

基于zone.js实现,,它能捕获异步操作。告诉Angular应用的状态可能已经改变了,在适当的时候触发变更检测机制。

1.4 变更检测的执行机制和顺序

只要有异步操作,就会触发变更检测。从根节点开始,从上到下遍历所有子组件(深度遍历)检测,直至最后一个组件达到稳定状态。

  1. 更新组件的输入属性
  2. 调用组件的生命周期的钩子函数OnChangesOnInitDoCheckAfterContentInit。`
  3. 更新当前组件的视图DOM
  4. 递归更新子组件…:当前组件的视图更新完成后,就会递归地更新子组件的视图。包含了以上三个步骤。
  5. 调用所有子组件生命周期的钩子ngAfterViewInit

1.5 常见的错误

如果违背了变更检测执行顺序,那么就会报错NG0100: ExpressionChangedAfterItHasBeenCheckedError。后果的例子待补充(比如:在子组件生命周期中,修改了父组件模板中使用到的值(包括子组件绑定的属性、模板使用到的<p>{{ name }}</p>))。

2 Angular的两种变更检测策略

CD:ChangeDetection

整个Angular应用是组件树

2.1 默认的脏检查Default策略

只要有异步操作,就会触发变更检测。从根节点开始,从上到下遍历所有子组件(深度遍历)检测,直至最后一个组件达到稳定状态。

2.2 OnPush策略

若为组件设置了OnPush策略,Angular的变更检测会跳过该组件及其子组件的检测。只有以下几种情况会触发该组件的变更检测:

  1. 只有输入数据的引用(@Input)改变时,组件才进行变更检测
  2. DOM事件触发时,才进行变更检测:从根组件开始往下遍历进行变更检测
  3. 手动触发变更检测(ChangeDetectorRef对象.detectChanges()):从该组件开始往下遍历进行变更检测

3 使用Angular的变更检测器手动管理变更检测

3.1 ApplicationRef

3.1.1 概念

在我们创建了Angular应用后,Angular会创建一个ApplicationRef的实例。它该应用根组件的引用。主要负责启动应用、处理全局的变更检测和应用关闭时执行清理工作

3.1.2 ApplicationRef对象的常用函数

  • bootstrap():启动应用将根组件挂载到DOM中
  • tick():手动触发一次变更检测
    • 该实例监听NgZoneonTurnDone事件。当该事件触发时,执行tick()触发变更检测
// 真实源码的非常简化版本。
class ApplicationRef {
  
  changeDetectorRefs:ChangeDetectorRef[] = [];
  
  constructor(private zone: NgZone) {
    this.zone.onTurnDone
      .subscribe(() => this.zone.run(() => this.tick());
  }
  
  tick() {
    this.changeDetectorRefs
      .forEach((ref) => ref.detectChanges());
  }
}
  • attachView()detachView():手动将视图附加到或分离出应用中
  • isStable:Observable<boolean>():检测应用是否稳定

3.2 ChangeDetectorRef:组件级别的变更检测器

3.2.1 概念

Angular会为每个组件实例生成一个变更检测器,用于管理变更检测
我们可以通过注入对象来获得

3.2.2 ChangeDetectorRef对象的常用函数

  • detectChanges(): 手动触发1次变更检测
  • markForCheck(): 标记当前组件及其父组件为脏检测状态,但不立即执行变更检测,等待下一轮变更检测时执行
  • detach(): 从变更检测树中分离当前组件,即暂时停止对当前组件的变更检测
  • reattach(): 重新将当前组件添加到变更检测树中,恢复对当前组件的变更检测
  • run(): 在 Zone 外部运行变更检测,可以用于优化性能

4 不必要的变更检测(待补充)

4.1 zone pollutions

Polluting the zone happens when we run an initialization logic that uses requestAnimationFrame, setTimeout or addEventListener.

comes from 3p libraries with triggers

move initializations outside the Angular zone

4.2 slow recalculation

4.3 skipping component subtrees

5 参考链接

一文弄懂 Angular 变更检测
可视化理解Angular变更检测顺序

  • 36
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值