代码之家  ›  专栏  ›  技术社区  ›  user3646699

Angular6管道过滤器在大型阵列上运行缓慢

  •  0
  • user3646699  · 技术社区  · 6 年前

    我有一个过滤器,它从一个大数组返回一个子集的项(这个数组中大约有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>
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   cyr_x    6 年前

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

    对ngForOf使用trackBy功能

    使用提供 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

    旁注

    请记住,角度开发模式下的性能远不如生产模式下的性能。在开发模式中,每个变更检测都运行两次。同时AOT模式将带来很多性能改进。

        2
  •  0
  •   Reactgular    6 年前

    你需要 为了获得性能,滤波器的前一状态。

    const originalValues = ['a', 'and', 'goo', 'apple', 'antelope', ...];
    

    当用户键入 a 您可以像这样过滤上面的值。

    const newValues = values.filter((value) => value.indexOf(input) !== -1);
    console.log(newValues);
    

    上面会印这样的东西。

    ['a', 'and', 'apple', 'antelope']
    

    input 你可以过滤 newValues 第二次。每次用户在其输入项中添加字母时,都可以筛选 以前的 结果又来了。只要用户使输入字符串变长。

    这不能通过管道完成,因为管道不记得以前的状态。你必须在组件中做一些特殊的事情来处理这个问题。

    中止 当你达到结果极限时。这样,当您发现限制为20时,就不会迭代整个集合。

     const newValues = [];
     for(let value of values) {
         if(newValues.length === 20) {
              break;
         }
         if(value.indexOf(input) !== -1) {
            newValues.push(value);
         }
     }