即使ChangeDetectionStrategy.OnPush

时间:2018-01-04 09:46:02

标签: angular performance

对于我的项目,我必须创建一个包含许多行(> 1000)的表,但这些表并不能很好地运行。为了演示这个问题,我创建了一个简单的应用程序,它包含一个可折叠的div和多个div,它们是通过* ngFor创建的。

只有一个组件(由角度CLI生成的app.component)。

html文件如下所示:

<div style="border:1px solid silver" (click)="toggleDiv()">TEST</div>

<div #divToToggle [ngStyle]="divStyle">
</div>


<div *ngFor="let row of rows">{{getName(row)}}</div>

Component-Class使用名为name的属性创建100个对象。模板中调用的方法getName将调用记录到控制台并返回name属性。

该类还提供了一种用于展开/折叠可折叠div的方法。

当我点击TEST-div时,执行toggleDiv()方法。并且:每次调用此方法时,都会调用所有行的方法getName()。

恕我直言,这是完全不必要的,并且会产生性能问题(使用css-animations等)。

由于组件使用ChangeDetectionStrategy.OnPush,我不明白,为什么angular会执行所有这些插值,即使没有任何变化!

有人有想法,如何改变这种行为?除非组件的任何输入参数发生变化,否则我希望使用angular来渲染表,而不是做任何事情。

尝试了Angular-Versions:4.4.4和5.1.3

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {

  rows: any[];

  expanded = false;
  divStyle: any;

  expandedStyle = {
    "height": "200px",
    "background-color": "orange"
  }
  collapsedStyle = {
    "display": "none"
  }

  constructor() {
    this.divStyle = this.expandedStyle;
    this.expanded = true;
    this.rows = this.createRows(100);
  }

  toggleDiv() {
    this.expanded = !this.expanded;
    if (this.expanded) {
      this.divStyle = this.expandedStyle;
    } else {
      this.divStyle = this.collapsedStyle;
    }    
  }

  getName(row:any): string {
    console.log("getName called")
    return row.name;
  }

  private createRows(count:number): any[] {
    let rows: any[] = [];

    for (let i=0; i < count; i++) {
      rows.push({
        name: "TEST " + (i+1)
      })
    }
    return rows;
  }
}

angular-CLI项目可以在[DropBox] [1]

找到

1 个答案:

答案 0 :(得分:2)

不要绑定到函数,而是绑定到属性

{{getName[row]}}

应该是

getName

其中OnPush是一个数组字段,其中包含每行的预先计算的值。

@Input()更新或组件中的事件处理程序收到事件((click)="...")|async管道收到事件时,

OnPush会运行更改检测。

OnPush只是在父组件运行更改检测时跳过组件的更改检测。

您还可以分离当前组件的更改检测器,以避免更严格地检查{{1}}本身的更改检测。