Angular - 加速过滤和显示 *ngFor

Angular - Speed up filtering and display of *ngFor

我有一个用户列表(目前大约有 450 个),我使用 onValueChanges 订阅和 javascript 过滤方法进行过滤。这似乎很慢。我相信它应该更快,但不确定是对象的实际过滤还是重新渲染 html 很慢。

当我在 stackBlitz 中重新创建它时,它非常快,所以我不确定为什么在我的项目中显示过滤的项目很慢。

实物略有不同,但相差不大

address: null
emailAddress: "fred.bloggs@example.com"
employeeId: 1
extraPhoneNumber: null
fullName: "Administrator Account"
jobTitle: "Learning Administrator"
personId: 52
phoneNumber: "01234567890"
photograph: null
searchTerms: "Administrator Account, 1, Learning Administrator"
totalAlerts: 0
totalCompleted: 0
totalMandatory: 0
totalOverdue: 0
totalToDo: 0

我的Html

<form class="" [formGroup]="myForm">
   <input type="text" class="input learningItemsSearch" placeholder="Search My Team"
     name="searchString" formControlName="searchString" />
</form>
 
<cdk-virtual-scroll-viewport itemSize="70" class="viewport">
 <div *ngFor="let user of filteredUsers">
            <table>
                <tbody>
                    <tr>
                        <td colspan="3">
                            {{ user.fullName }}
                        </td>
                        <td colspan="3">
                            {{ user.jobTitle }}
                        </td>
                        <td colspan="3">
                                {{ user.emailAddress }}
                        </td>
                        <td colspan="3">
                               {{ user.phoneNumber }}
                       </td>      
                  </tr>
             </tbody>
         </table>
    </div>
 </cdk-virtual-scroll-viewport>

我的组件

this.myForm.valueChanges.pipe(
  debounceTime(400),
  distinctUntilChanged(),
  tap((value: any) => {
      let searchTerm = value.searchString;
      this.filteredUsers = this.users.filter((userName) =>
        userName.searchTerms
          .toLowerCase()
          .indexOf(searchTerm.toLowerCase()) !== -1)
  })
).subscribe( );

这是筛选对象数组的最有效方法吗?是否还有其他原因导致它似乎需要一些时间才能显示在屏幕上? html 没有什么太复杂的。我正在使用 cdk-virtual-scroll 看看它是否会加载得更快,但没有它它也很慢。

StackBlitz here

编辑: 我忘了使用 *cdkVirtualFor 而不是 *ngFor。现在快多了。我认为添加下面提到的 trackby 也有帮助。

您可能会看到使用 trackBy 功能 https://angular.io/api/core/TrackByFunction 的渲染加速。将以下函数添加到您的组件中:

public trackById = (_: number, item: any) => item.id; // or userId, whatever is the unique identifier

然后修改你的模板:

<div *cdkVirtualFor="let user of filteredUsers; trackBy:trackById">

我认为 2 可能会导致明显的性能变化(当然 3 很长)

1.保留与 -1

的比较
// before: userName.searchTerms.toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1
userName.searchTerms.toLowerCase().includes(searchTerm.toLowerCase())

2。看起来很奇怪,你想要每个用户一个 table,你确定它不应该是一个 table 与用户行行吗?

<tr *ngFor="let user of filteredUsers">
  <td colspan="3">{{ user.fullName }}</td>
  <td colspan="3">{{ user.jobTitle }}</td>
  <td colspan="3">{{ user.emailAddress }}</td>
  <td colspan="3">{{ user.phoneNumber }}</td>      
</tr>

3。 JohnD

的回答中提到的 trackBy 的使用

4.订阅控件而不是整个表单

this.myForm.controls.searchString.valueChanges
      .pipe(
        debounceTime(400),
        distinctUntilChanged(),
        tap((searchTerm: string) => {