详解Angular中的变更检测(十)- 变更检测策略之OnPush

202 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

Onpush策略

Angular 还提供了一种OnPush策略,我们可以修改组件装饰器的 changeDetection来更改变更检测的策略。

@Component({
    selector: 'my-test',
    // 设置变化检测的策略
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: ...
})
export class MyTestComponent {
    ...
}

设置为 OnPush 策略后,Angular 每次触发变化检测后会跳过该组件和该组件的所以子组件变化检测。但是,有一些情况下,依然还是会触发变更检测的。

OnPush 策略下,只有以下这几种情况才会触发组件的变化检测:

输入属性值(@Input)更改

在默认的变更检测策略中,Angular 将在 @Input() 数据发生更改或修改时执行变化检测,使用该OnPush时,传入@Input()的值必须是一个新的引用才会触发变化检测。

当前组件或子组件之一触发了事件

如果OnPush组件或其子组件之一触发(DOM/BOM)事件,例如 click,则将触发变化检测(针对组件树中的所有组件)。具体都有哪些事件会触发变更检测,可以查阅相关资料。

需要注意的是在OnPush策略中,以下操作不会触发变化检测:

  • setTimeout()
  • setInterval()
  • Promise.resolve().then()
  • this.http.get('...').subscribe()
  • ......

手动触发变化检测

有三种手动触发变更检测的方法:

  • detectChanges() : 它会触发当前组件和子组件的变化检测;
  • markForCheck() :它不会触发变更检测,但是会把当前的OnPush组件和所有的父组件为OnPush的组件 标记为需要检测状态,在当前或者下一个变化检测周期进行检测;
  • ApplicationRef.tick() : 它会根据组件的变化检测策略,触发整个应用程序的更改检测;

可以通过 在线Demo,更直观的了解这几种触发变化检测的方式。

使用 async 管道后,observable 值发生了变化

内置的 AsyncPipe ****订阅一个 observable 并返回它发出的最新值。每次发出新值时的内部AsyncPipe调用 markForCheck

private _updateLatestValue(async: any, value: Object): void {
  if (async === this._obj) {
    this._latestValue = value;
    this._ref.markForCheck();
  }
}

现在已经了解了OnPush变更检测策略,以及在4种情况下它会自动触发变更检测,这几种情况无需记忆,用的多了自然就印象深刻了。