只需几步即可加快MatTable渲染速度

通常,大多数应用程序都是由各种列表和表组成的。为了避免每次都重新发明轮子,我和许多人一样,经常使用Angular Material表

后来,这些表增长了,文本数据和嵌套元素都放置在单元格中。所有这些都会增长,并成为用户计算机上的良好负载。当然,没有人喜欢这个。

在我的上一个家庭项目中,有一张桌子,桌子的单元格中大部分都充满了各种字段(您甚至可以说这是一个很大的形式)。

渲染大约需要8秒钟(40 x 40表格)。

那么如何为大型列表优化MatTable?

图片

测试用例


为了帮助他人处理此问题,我编写了一个小型测试应用程序。相同的MatTable表,共有五列(第一列是元素的ID,其余为常规的MatFormField文本字段)。



看起来这是一个简单的表,但是即使使该表消耗100的时间也不会超过或少于2秒(哦,这种材料及其“顶级”性能)。



在这种情况下,渲染本身仅花费了(860 ms),但是页面冻结了2.2秒,用户感到不高兴。

好吧,让我们尝试渲染一个包含300行的表。而鼓声,我们稍等片刻,发现总共花了将近10秒钟的脚本和渲染时间。也就是说,在用户希望显示300行这样的表的情况下,他的页面将冻结10秒。这是非常可怕和令人惊奇的(实际上不是)。



实际上,我仍在尝试绘制1000个元素所需的时间,但是我可怜的i7无法忍受它,并且页面不断掉落。
稍后,我们将尝试使用已应用的解决方案进行此操作。

解决问题


因此,每个人都可以使用基于浏览器的实用程序进行测量,但是没有解决此问题的方法。

这个决定是通过对问题的实质进行推理而导致的。
对问题的正确理解至少已经解决了一半。
我认为每个人都明白,这是发生,因为该表中的数据首先由脚本处理,然后在吐出一块反过来,这正是我们看到具有特征性的悬挂的原因。

发现问题。现在还有待解决。想到第一个解决方案。如果问题是一次处理所有数据,则需要使表分部分处理数据。

但是该怎么做呢?

让我们思考一下开箱即用的功能。首先想到的是“跟踪依据”功能。更改数据源时,将不重新呈现整个表,而仅重新更改它。

让我们将此函数添加到表中:

<mat-table [trackBy]="trackByFn" [dataSource]="commonDataSource">

是的,但是我们没有这样的条件,即表数据以某种方式发生了变化,而这并不是现在的话题。但是,如果我们编写Pipe会怎样呢?在初始化数据源时,它将破坏数据并将其分批提供给表。反过来,trackBy函数将有助于避免完整的渲染器。

@Pipe({
  name: 'splitSchedule'
})
export class SplitPipe implements PipeTransform {
  public transform(value: any, takeBy: number = 4, throttleTime: number = 40): Observable<Array<any>> {
    return Array.isArray(value)
      ? this.getSplittedThread(value, takeBy, throttleTime)
      : of(value);
  }

  private getSplittedThread(data: Array<any>, takeBy: number, throttleTime: number): Observable<Array<any>> {
    const repeatNumber = Math.ceil(data.length / takeBy);
    return timer(0, throttleTime).pipe(
      map((current) => data.slice(0, takeBy * ++current)),
      take(repeatNumber)
    );
  }
}

这是一小段代码,将帮助您的硬件呈现如此大的表。

将此管道应用于我们的数据源。


<mat-table [trackBy]="trackByFn"
           [dataSource]="commonDataSource | splitSchedule | async">

现在让我们尝试进行测量。渲染100、300和1000个元素。







我们看到了什么?真正的成功不是我们所期望的:

  • 300个元素渲染速度提高1秒
  • 在11秒内渲染了1000个,并且标签没有消失
  • 和100个元素的渲染时间通常会长150毫秒

但是不要急于下结论,让我们先看看两种情况下页面的行为。





如您所见,在通常情况下,页面会冻结几秒钟,此时用户无法执行任何操作,同时将我们的管道与trackBy链接一起使用时,用户几乎可以立即进行表初始化,并且在使用应用程序时不会造成任何不适。

希望本文能对某人有所帮助。

测试应用程序的源代码在Stack Blitz上

All Articles