详解Angular中的变更检测(九)- 变更检测策略之Default

83 阅读3分钟

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

终于到了变更策略的部分,这一部分是Angular的核心部分之一,也是和工作联系最紧密的部分。

ChangeDetection

先来回顾一下Angular的变更检测,变更检测是用于检测程序的内部状态,然后反映到UI上。在组件初始化阶段后,引起状态变化的内容【通常都是异步的】,Events事件触发、XHR发送的Http等请求通过接收内容改变某些状态、timers定时任务等。

事件执行通常是通过ApplicationRef监听NgZone的onMicroTaskEmpty,然后执行检测。

变更检测策略

应用状态通常会构建CD树(ChangeDetection树),Angular默认策略是将所有的CD树都跑一边。 在前面我们已经介绍了,组件树,组件变更检测器构成的树。 image.png Default策略的情况下,Angular会从根组件从上往下检查所有的组件,也就是执行每个组件的变更检测,那这样会不会效率很低,执行很慢啊,当然不会,Angular对每个组件进行变更检测的速度非常快。而在OnPush策略下,Angular依然会从根组件从上往下检查组件,但是会跳过标记为OnPush的组件,以及它的子组件。

Angular 提供了两种运行变更检测的策略:

  • Default
  • OnPush

Default策略

默认情况下,Angular 使用ChangeDetectionStrategy.Default变更检测策略,每次事件触发变化检测(如用户事件、计时器、XHR、promise 等)时,此默认策略都会从上到下检查组件树中的每个组件。这种对组件的依赖关系不做任何假设的保守检查方式称为脏检查。这种策略使用起来很简单,开发者无需关心它的工作方式。如果在定义Component的时候,没有指定变更检测策略,那么就采用这种变更检测策略。

例子

我们来看一个例子,现在有两个组件,AppComponent,和MainComponent。

@Component({
  template: `
    <h1>{{runChangeDetection}}</h1>
  `
})
export class MainComponent {
  get runChangeDetection() {
    console.log('Checking the view');
    return true;
  }
}
@Component({
  template: `
    <main></main>
    <button (click)="onClick()">Change</button>
  `
})
export class AppComponent  {
  onClick() {}
}

问题来了:

  • 页面加载完后,控制台上输出了几次Checking the view?
  • 用户点击了Change button后,控制台上输出了几次Checking the view?

组件初始化阶段,会执行两次tick()方法,tick方法里会先执行一次detectChanges(),如果是dev模式,会执行一次checkNoChanges(),所以是4次。点击button的后,只会触发一次tick(),所以是两次。 这个之前的文章中做了详细的解释,这里就不在赘述了,不清楚的小伙伴可以找之前的文章看一下哦。

上面我们说过,Angular对每个组件进行变更检测的速度非常快,但是如果组件树过于庞大,也就是组件过多的情况下,整个应用的性能必然会受到影响。 那怎么办呢?那就使用OnPush策略吧。 下一篇文章,我们会详细讲解OnPush策略。