首页 > 解决方案 > Angular6管道过滤器在大型阵列上运行缓慢

问题描述

我有这个过滤器,它从一个大数组中返回一个项目的子集(这个数组中大约有 500 个项目)

    import { Injectable, Pipe, PipeTransform } from '@angular/core';

    @Pipe({
     name: 'searchFilter'
    })

    @Injectable()
    export class FilterArrayPipe implements PipeTransform {
     transform(value: any, ...args): any {
        // tslint:disable-next-line:no-unused-expression
        console.log(value, args);
       if ( typeof args[0] === 'undefined') {
        return value;
       } else if (value) {
           return value.filter(item => {
               // tslint:disable-next-line:prefer-const
               for (let key in item) {
                   if ((typeof item[key] === 'string' || item[key] instanceof String) &&
                        (item[key].toUpperCase().indexOf(args[0].toUpperCase()) !== -1)) {
                            return true;
                        }
               }
           });
       }
    }

    }

每当我在文本框中键入时,字符实际显示在框中需要几秒钟,再过几秒钟返回更新列表以返回搜索项。

我尝试添加slice:0:10以限制屏幕上的项目数量,但它有同样的问题,所以我猜测缓慢是由于大数组而不是屏幕渲染。

我已经和后端开发人员谈过了,由于这个数组被其他人使用,他不会修改它。我能做些什么来提高性能?

编辑:包括html代码:

    <form *ngFor='let subarray of array | searchFilter: filterText | slice:0:20 ; let i = index;' #form="ngForm" (ngSubmit)="Save(form)">
      <fieldset>
            <input type="text" name="country" [ngModel]="subarray.country ">
            <input type="number" name="number" [ngModel]="subarray.number ">
            ............about 24 input fileds in total ..............
       </fieldset>
    </form>

标签: javascriptangularangular6

解决方案


您应该尝试一些性能改进:

对 ngForOf 使用 trackBy-function

使用为指令提供一个trackBy函数ngForOf,例如通过索引跟踪所有 DOM 元素:

// template:
<div *ngFor="let subarray of array; trackBy:trackByIndex">
  ...
</div>

// component:

public trackByIndex(index: number, value: any)
{
  return index;
}

不要使用管道过滤数据 (用于不纯管道)

不要使用管道过滤大型数组,因为每次为组件运行 changedetection 时都会调用它。

例如,如果搜索输入发生变化,您可以过滤大数组:

// component:
public originalData: any[] = [...];
public filteredData: any[] = this.originalData;

// ...

public filterData(searchString: string)
{
   this.filteredData = this.originalData.filter(item => {
     // your filter logic
   })
}

通过可搜索的字符串丰富您的每个项目

通过可搜索的字符串丰富数组中的每个项目。如果您想搜索一个项目的所有值,只需映射一次数组并将一个新键附加到该项目,如:

this.originalData = this.dataService.getData().map(item => {
   return {
     ...item,
     searchableString: Object.values(item).join(':'),
   }
})

这可以防止您在过滤时遍历每个项目。您只需在该属性内搜索输入字符串。

item.searchableString.indexOf(input) > -1

其他技术

  • 去抖动用户搜索输入
  • 使用 BehaviorSubject 过滤服务内的数据,ChangeDetectionStrategy.OnPush并将数据作为列表组件的输入

边注

请记住,Angular 开发模式下的性能远低于生产模式。在开发模式下,每个更改检测都会运行两次。AOT-mode也会带来很多性能提升。


推荐阅读