【问题标题】:Angular Material Datatable loads slowAngular Material Datatable 加载缓慢
【发布时间】:2020-04-26 13:18:21
【问题描述】:

我的 Angular Material Application 遇到了一些问题。我正在使用带有分页器的数据表。 数据不必排序。

在加载数据时,我正在展示一个 mat-spinner

<div *ngIf="schools !== undefined">
        <mat-spinner *ngIf="showSpinner" style="margin:0 auto;"></mat-spinner>
        <div *ngIf="!showSpinner">
            Keine Daten gefunden.
        </div>
</div>
<div *ngIf="schools !== undefined">
   <mat-table [dataSource]="dataSource"> 
      ...
   </mat-table>
   <mat-paginator [pageSizeOptions]="[10, 20, 50, 100]" [pageSize]="20" showFirstLastButtons></mat-paginator>
</div>

在正常情况下,我正在加载数据,当加载数据并显示数据时微调器停止旋转。这工作得很好。

但是对于一个大约有 400 行的表格,我遇到了这个问题:

成功加载数据后,微调器会变得非常缓慢大约一秒钟,并且数据表会显示所有内容。 (由分页器分隔)

从 api 加载数据大约需要 400 毫秒,解析它大约需要 3 毫秒,所以这应该不是问题。

我正在加载这样的数据:

ngOnInit() {
    setTimeout(() => {
      this.showSpinner = false;
    }, 5000);

    this.userID = this.authService.getCurrentUser.uid;
    this.loadData();
}

loadData() {
    this.apiService.getSchools().subscribe((schoolsData: any) => {
      this.schools = this.refParser.parse(schoolsData);
      this.dataSource = new MatTableDataSource(this.schools);

      this.cdr.detectChanges();
      this.dataSource.paginator = this.paginator;
    });
}

我已经在 stackoverflow 上找到了一篇对我有帮助的帖子 (Angular 6 MatTable Performance in 1000 rows.)。 但这对我没有帮助:(

我是这样尝试的:

ngOnInit() {
    setTimeout(() => {
      this.showSpinner = false;
    }, 5000);

    this.userID = this.authService.getCurrentUser.uid;
    //this.loadData();
    this.dataSource = new MatTableDataSource();

    this.dataSource.paginator = this.paginator;
}

ngAfterViewInit(){
    setTimeout(() => {
      this.apiService.getSchools().subscribe((schoolsData: any) => {
        this.schools = this.refParser.parse(schoolsData);
        this.dataSource.data = this.schools;
        this.cdr.detectChanges();
      })
    })
}

它没有给我任何性能提升。唯一发生的事情是,分页器不再工作了。

有人知道什么可以帮助我提高应用程序的性能吗?

感谢您的回答:)

【问题讨论】:

标签: angular performance datatable angular-material


【解决方案1】:

我过去也遇到过同样的问题, Mat-Table 处理更改检测本身,因此它不是 mat table 的问题, 是数据源设置错误。

如果您一次性传递所有数据,它将仅在第一次加载时呈现整个数据并显示滞后。

由于您使用的是分页器,因此您应该将数据源分解为 pageSize,以便在加载时仅呈现 20 个元素。

创建一个新的分页器实例:actualPaginator: MatPaginator;

@ViewChild(MatPaginator, {static: false})
  set paginator(value: MatPaginator) {
    this.actualPaginator = value;
  }

this.actualPaginator.pageIndex = Math.ceil(this.schools.length/this.actualPaginator.pageSize) - 1;

 let nextPageData: any[] = [];
 nextPageData = this.schools.slice((this.actualPaginator.pageSize * this.actualPaginator.pageIndex),(this.actualPaginator.pageSize * (this.actualPaginator.pageIndex + 1)));
 this.dataSource.data = nextPageData;

因此,分发您的 this.schools 数据并按页面大小计数加载它,在单击下一个按钮时使用 this.schools 数据的下一个插槽更改数据源将解决您的问题。

您必须通过创建新的 MatPaginator 实例来单独操作 mat-paginator,这是关键解决方案。

【讨论】:

  • 非常感谢您完全解决了我的问题但是我在处理分页器时仍然遇到了一些麻烦。您是否有解释处理分页器的来源?
  • FWIW 我赞成这个答案,但后来找到了对正在发生的事情的更清晰的解释。这完全取决于您设置数据和分页器的顺序。正确的顺序是数据最后(所以分页器在那里防止所有数据在传入时被呈现)。看到这个答案:stackoverflow.com/a/51296374/5185252
【解决方案2】:

对我来说,问题是在ngOnChanges 上分配数据源,我将其更改为在ngAfterViewInit 上分配,它的工作速度更快。

【讨论】:

    【解决方案3】:

    你应该只交换两行代码的位置。

    你的代码

    this.dataSource = new MatTableDataSource(this.schools);
    ...
    this.dataSource.paginator = this.paginator;
    

    您是在告诉材料渲染所有表格,并且只有在分页器渲染切片之后

    和新代码

    this.dataSource.paginator = this.paginator;
    ...
    this.dataSource = new MatTableDataSource(this.schools);
    

    【讨论】:

    • 你有正确的想法,但执行是错误的。问题确实如您所描述:必须在设置数据之前设置分页器。然而,通过最后实例化一个新的数据源,你失去了分页器的配置。不要重新创建dataSource,只需设置dataSource.data 设置dataSource.paginator
    【解决方案4】:

    您应该在加载完数据后禁用微调器:

    loadData() {
        this.apiService.getSchools().subscribe((schoolsData: any) => {
          this.schools = this.refParser.parse(schoolsData);
          this.dataSource = new MatTableDataSource(this.schools);
          this.showSpinner = false; // here!
    
          this.cdr.detectChanges();
          this.dataSource.paginator = this.paginator;
        });
    

    也许像这样改变你的模板:

    <mat-spinner *ngIf="showSpinner" style="margin:0 auto;"></mat-spinner>
    <div *ngIf="!shools && !showSpinner">
        Keine Daten gefunden.
    </div>
    
    <div *ngIf="dataSource">
       <mat-table [dataSource]="dataSource"> 
          ...
       </mat-table>
       <mat-paginator [pageSizeOptions]="[10, 20, 50, 100]" [pageSize]="20" showFirstLastButtons></mat-paginator>
    </div>
    

    【讨论】:

    • 很遗憾,这无法解决我的问题,但谢谢,您完全正确,解决方案是使用微调器的更好方法。
    【解决方案5】:

    @dimson-d 有一个正确的想法:你需要在设置数据之前设置分页器

    constructor:
    this.dataSource = new MatTableDataSource([]);
    ...
    
    ngAfterViewInit:
    this.dataSource.paginator = this.paginator
    ...
    this.dataSource.data = this.schools
    

    这保证了数据集在被渲染到表格之前会被分页。接收数据时不要实例化新的 MatTableDataSource,因为这将删除分页器引用。只需设置dataSource.data

    您尝试的解决方案导致分页器停止工作并且没有提高性能的原因可能是因为在 ngOnInit 中设置了分页器引用,此时它为空(假设您使用的是 @ViewChild(MatPaginator))。因此,您仍在对整个未分页的数据集进行操作。

    【讨论】:

      猜你喜欢
      • 2010-11-11
      • 2018-07-06
      • 2018-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      相关资源
      最近更新 更多