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');
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。