我有这个过滤器,可以从一个大数组中返回部分项目(此数组中大约有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>
答案 0 :(得分:3)
您应该尝试一些性能改进:
对ngForOf使用trackBy函数
使用为trackBy
指令提供ngForOf
函数,例如通过索引来跟踪所有DOM元素:
// template:
<div *ngFor="let subarray of array; trackBy:trackByIndex">
...
</div>
// component:
public trackByIndex(index: number, value: any)
{
return index;
}
请勿使用管道过滤数据 (用于不纯管道)
不要使用管道来过滤大型数组,因为每次组件更改检测运行时都会调用它。
例如,如果搜索输入发生更改,则可以过滤大型数组:
// 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
其他技术
ChangeDetectionStrategy.OnPush
一起过滤服务内部的数据,并将数据作为列表组件的输入边注
请记住,角度开发模式下的性能远比生产模式下的性能差。在开发模式下,每个变更检测运行两次。此外,AOT模式将带来很多性能改进。
答案 1 :(得分:0)
您需要记住过滤器的先前状态才能获得性能。
让我们假设您有一长串500个看起来像这样的字符串。
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);
}
}
答案 2 :(得分:0)
另一种可能是记忆模式。
例如,如果那是您的管道
// excerpt
transform(value: any, ...args: any[]): any {
return this.myOwnTransformingMethod(args, value);
}
您可以将记事装饰器用于此方法,例如
@memo()
private myOwnTransformingMethod(args: any[], value: any) {
// do some filtering or transformations and
return value;
}
您不必自己实现该模式。您可以使用一种(MIT许可证):
npm i memo-decorator -S
并将其导入您的whatever.pipe.ts
import memo from 'memo-decorator';