Angular Component 性能优化changeDetection?:ChangeDetectionStrategy#OnPush

背景

使用 angular cli 生成一个组件,默认没有配置changeDetection ,也就是changeDetection 为默认值ChangeDetectionStrategy#Default, 正常情况应该没有什么问题,最近在工作中遇到一个比较复杂的组件,经过很长时间的版本迭代,用各种方法添加了各种业务实际需求但不长见到的功能。组件放到页面后,其他表单组件卡顿。翻看其他组件库的源码,发现组件都配置了changeDetection?:ChangeDetectionStrategy#OnPush,自己的组件配置上,效果那是杠杠的。

changeDetection 到底有什么作用

文档上的解释: 链接

changeDetection: 用于当前组件的变更检测策略。

可以配置的值有2个

ChangeDetectionStrategy#OnPush 把策略设置为 CheckOnce(按需)。

ChangeDetectionStrategy#Default 把策略设置为 CheckAlways。

光看这些,肯定一脸懵逼,默认的配置ChangeDetectionStrategy#Default ,有什么好处,为什么会成为默认配置项

一个组件changeComponent,有一个输入框,有一个子组件 fooComponent, fooComponent组件中details 是一个get 属性,每次changeComponent 中输入框输入,detail get 都会执行

如果fooComponent 设置了

@Component({
  selector: 'app-foo',
  templateUrl: './foo.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  styleUrls: ['./foo.component.less']
})
export class FooComponent implements OnInit {
  // 传入参数
  @Input() father: string;

  public get detail() {
    console.log('get detail');
    return 'this is a detail string for test';
  }
  
  ngOnInit(): void {
   
  }
}

结果是这样的:

但是组件的father属性改变后,get detail 也会执行:

结论

changeDetection 能改变组件视图的变检规则,在OnPush模式下,之后组件的输入属性发生变化,视图更新。组件追求极致性能,最好使用OnPush 模式。

附完整代码

app-change

@Component({
  selector: 'app-change',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template:`
    <h2>changeComponent</h2>
    <hr>
    input in father component
    <input type="text" [(ngModel)]="value">

    <button (click)="changeName()">
      change name
    </button>
    <hr>
    <app-foo [father]="name"></app-foo>
  `,

})
export class ChangeComponent implements OnInit {
  private _name:string = 'foo';
  get name(): string {
    // console.log('get name');
    return this._name;
  }
  set name (value) {
    this._name = value;
  }
  value: string;
  items: Array<any> = ['Really', 'Super', 'Greater'];

  constructor() { }

  ngOnInit(): void {
  }

  changeName(){
    //
    this.name = "chened name";
  }

app-foo

@Component({
  selector: 'app-foo',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template:`
      <h2>fooComment</h2>
      <p>father:{{father}}</p>
      <section>
        detail: {{detail}}
      </section>
  `,
})
export class FooComponent implements OnInit {
  // 传入参数
  @Input() father: string;

  public get detail() {
    console.log('get detail');
    return 'this is a detail string for test';
  }

  ngOnInit(): void {

  }

  ngDoCheck(): void {
    console.log('foo ngDoCheck');
  }
  ngAfterViewChecked(): void {
    console.log('foo ngAfterViewChecked');
  }

}

today
906 声望41 粉丝