Angular 6 MatTable性能1000行.

mos*_* cs 15 angular-material angular-material2 angular angular-cdk

我在我的项目中使用角度材质,我使用Mat-Table为每个表渲染1000个产品/行.当表格改为分页(我们使用后端分页)到1000行时,性能变得非常慢,我甚至无法在文本框中写入.

我试图调试问题,所以我把日志放在一个列模板上,这样我就可以看到渲染是如何工作的.

即使我将鼠标悬停在表格标题上,我也看到它会重新呈现所有行.是否有可能将变更检测控制为ChangeDetectionStrategy.OnPush

在此输入图像描述

小智 27

不确定这是否会对您的情况有所帮助,因为没有代码但我们发现如果设置数据源分页器之前设置了大型数据集,则MatTable加载速度非常慢.

例如 - 这需要几秒钟来渲染......

dataSource: MatTableDataSource<LocationItem> = new MatTableDataSource();
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;

ngOnInit() {
  this.dataSource.data = [GetLargeDataSet];
}

ngAfterViewInit() {
  this.dataSource.sort = this.sort;
  this.dataSource.paginator = this.paginator;
}
Run Code Online (Sandbox Code Playgroud)

......但这很快

ngOnInit() {
  // data loaded after view init 
}

ngAfterViewInit() {
  this.dataSource.sort = this.sort;
  this.dataSource.paginator = this.paginator;

  /* now it's okay to set large data source... */
  this.dataSource.data = [GetLargeDataSet];
}
Run Code Online (Sandbox Code Playgroud)

顺便说一下,我们第二次访问组件时才发现这个问题,因为来自服务器的大型数据集正在被缓存,并且在第二次访问组件时立即可用.如果要将该代码保留在ngOnInit函数中,另一个选项是将.delay(100)添加到您的observable.

无论如何,这可能会或可能不会帮助您的情况.

  • 我希望我可以投票100万次!太糟糕了我决定尝试寻找一个答案,因为我花了两天的时间来完成我的整个应用程序,认为我有一些代码被多次调用并降低了表性能,因为即使数据源中有100个项目,它的更新速度也很慢. (2认同)
  • 我几乎决定使用另一个数据表库。谢了哥们。这个性能问题至少应该在文档中指定! (2认同)

KMJ*_*sen 10

从父组件传递下来的大型数据集 Observable

经过一番努力,我能够将这篇文章中的许多不同答案结合起来,包括@turneye的上面和OP选择的正确答案,以及另一个类似的SO帖子的答案,这里这里

页面上的父组件以及多个子组件(包括分页MatTable组件)需要大约 1000 行。

数据加载时间小于 500 毫秒,但页面平均需要 15 秒才能渲染,因为最初我只是传递一个MatTableDataSource已分配数据的对象。

解决方案:

  1. 传递带有数据的 observable,然后在视图初始化后订阅它,在设置和MatTableDataSource.data设置属性。MatPaginatorMatSort
  2. 在装饰器配置中设置changeDetection为。ChangeDetectionStrategy.OnPushComponent
  3. 在可观察主体中设置MatDataSource.data属性后,告诉 Angular 检测变化ChangeDetectorRef.detectChanges()

现在,完整的 DOM 总共渲染时间约为 1 秒,考虑到需要立即呈现的数据量,这已经足够了。

这是一个精简的示例:

@Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    selector: 'app-dynamic-grid',
    templateUrl: './dynamic-grid.component.html',
    styleUrls: ['./dynamic-grid.component.scss'],
  })
  export class DynamicGridComponent implements OnInit, AfterViewInit {
    @Input() public dataSource$: Observable<any[]>;
  
    public matDataSource = new MatTableDataSource<any>();
  
    @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
    @ViewChild(MatSort, { static: true }) sort: MatSort;
  
    constructor(private changeDetectorRef: ChangeDetectorRef) {}
  
    ngOnInit(): void {}
  
    ngAfterViewInit() {
      this.matDataSource.paginator = this.paginator;
      this.matDataSource.sort = this.sort;
  
      this.dataSource$.subscribe(x => {
        this.matDataSource.data = x;

        // The important part:
        this.changeDetectorRef.detectChanges();
      });
 
    }
}
Run Code Online (Sandbox Code Playgroud)


Pie*_*Duc 6

扩展@Turneye 的回答。它发生的原因是因为在渲染所有行之后设置了分页器,因为这就是ngAfterViewInit钩子告诉你的。

所以它首先呈现来自数据源的所有行,然后它看到:“嘿,我得到了一个分页器,让我删除所有行(寻呼机计数除外)”。这在大型数据集和/或复杂的表格单元格模板上显然非常慢。

您可以使用此解决{static: true}你的选项@ViewChild。这将使分页器在ngOnInit生命周期钩子内可用,并且在任何行被渲染之前:

窃取他的代码,可以改成这样,还是有一个快表:

readonly dataSource: MatTableDataSource<LocationItem> = new MatTableDataSource();

@ViewChild(MatSort, { static: true }) sort: MatSort;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;

ngOnInit() {
  this.dataSource.data = [ GetLargeDataSet ];
  this.dataSource.sort = this.sort;
  this.dataSource.paginator = this.paginator;
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您mat-paginator在结构指令中,这将不起作用*ngIf


另一个性能问题可能是您必须声明一个trackBy函数:

为了提高性能,可以向表提供一个 trackBy 函数,类似于 Angular 的 ngFor trackBy。这通知表如何唯一标识行以跟踪数据如何随每次更新而变化。

<table mat-table [dataSource]="dataSource" [trackBy]="myTrackById">
Run Code Online (Sandbox Code Playgroud)


mos*_* cs 5

我已经解决了这个问题,我通过将表格包装在自定义(网格)组件中并控制changeDetection组件的状态ChangeDetectionStrategy.OnPush以及何时渲染更新来提高性能ChangeDetectorRef.detectChanges()

  • 您能对此进行扩展吗? (2认同)