为什么 ng-select 提前输入会导致性能问题?
why is ng-select type ahead causing performance issues?
我正在使用 ng-select 对 select 列表中的项目进行提前输入过滤。当您键入过滤列表中第一项的结果时,性能快如闪电。然而,在你 select 第一项之后,一切都变得 非常 慢。我不太了解 rxjs,无法理解瓶颈是什么。
我的模板:
<label>Select Employees:</label>
<ng-select [items]="people$ | async"
bindLabel="full_name"
[multiple]="true"
[addTag]="addCustomItem"
[hideSelected]="true"
[trackByFn]="trackByFn"
[minTermLength]="2"
[loading]="peopleLoading"
typeToSearchText="Please enter 2 or more characters (of first OR last name)"
[typeahead]="peopleInput$"
[(ngModel)]="selectedPersons">
</ng-select>
<br>
<div style="margin-bottom:100px">Selected persons: {{selectedPersons | json}}</div>
我的 Typescript 组件:
import { Component, OnInit } from '@angular/core';
import { concat, Observable, of, Subject } from 'rxjs';
import { Person, Employee } from './data.service';
import { catchError, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
import { NodeHTTPService } from '../../node-http.service';
@Component({
selector: 'app-employee-picker',
templateUrl: './employee-picker.component.html',
styleUrls: ['./employee-picker.component.css']
})
export class EmployeePickerComponent implements OnInit {
people$: any/*Observable<Employee[]>*/; // you can see I had an issue here.
peopleLoading = false;
peopleInput$ = new Subject<string>();
selectedPersons: Employee[];
addCustomItem: boolean = false; // setting this to true allows users to add custom items not in the select list.
constructor(private _nodeHTTPService: NodeHTTPService) {
}
ngOnInit() {
this.loadPeople();
}
trackByFn(item: Person) {
return item.id;
}
private loadPeople() {
this.people$ = concat(
of([]), // default items
this.peopleInput$.pipe(
distinctUntilChanged(),
tap(() => this.peopleLoading = true),
switchMap(term => this._nodeHTTPService.getUsers(term).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.peopleLoading = false)
))
)
);
console.log('this.people$: ', this.people$)
}
}
NodeHttpService:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { CdfServiceService } from "./cdf-service.service";
@Injectable({
providedIn: 'root'
})
export class NodeHTTPService {
constructor(private http: HttpClient, private _cdfServiceService: CdfServiceService) { }
getUsers(i) {
if (!i) { i = ''};
let users = this.http.get(`https://chq-smscqa01.chq.ei/db/users?user=${i}`)
return users;
}
}
非常感谢您对这个问题的任何意见!谢谢。
您可以立即做两件事来提高性能
1) 通过启用虚拟滚动实现 DOM 回收。
如documentation所述,您可以将virtualScroll
输入属性设置为true
,这样只会加载指定数量的DOM ] 元素,它基于 ng-select 下拉列表的当前滚动容器的高度。
2) 在服务器端实现分页。这将减少每个 HTTP 请求的负载,从而使其在前端和后端都更快。
您可以将 virtualScroll
添加到您的 <ng-select>
:
[virtualScroll]="true"
我正在使用 ng-select 对 select 列表中的项目进行提前输入过滤。当您键入过滤列表中第一项的结果时,性能快如闪电。然而,在你 select 第一项之后,一切都变得 非常 慢。我不太了解 rxjs,无法理解瓶颈是什么。
我的模板:
<label>Select Employees:</label>
<ng-select [items]="people$ | async"
bindLabel="full_name"
[multiple]="true"
[addTag]="addCustomItem"
[hideSelected]="true"
[trackByFn]="trackByFn"
[minTermLength]="2"
[loading]="peopleLoading"
typeToSearchText="Please enter 2 or more characters (of first OR last name)"
[typeahead]="peopleInput$"
[(ngModel)]="selectedPersons">
</ng-select>
<br>
<div style="margin-bottom:100px">Selected persons: {{selectedPersons | json}}</div>
我的 Typescript 组件:
import { Component, OnInit } from '@angular/core';
import { concat, Observable, of, Subject } from 'rxjs';
import { Person, Employee } from './data.service';
import { catchError, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
import { NodeHTTPService } from '../../node-http.service';
@Component({
selector: 'app-employee-picker',
templateUrl: './employee-picker.component.html',
styleUrls: ['./employee-picker.component.css']
})
export class EmployeePickerComponent implements OnInit {
people$: any/*Observable<Employee[]>*/; // you can see I had an issue here.
peopleLoading = false;
peopleInput$ = new Subject<string>();
selectedPersons: Employee[];
addCustomItem: boolean = false; // setting this to true allows users to add custom items not in the select list.
constructor(private _nodeHTTPService: NodeHTTPService) {
}
ngOnInit() {
this.loadPeople();
}
trackByFn(item: Person) {
return item.id;
}
private loadPeople() {
this.people$ = concat(
of([]), // default items
this.peopleInput$.pipe(
distinctUntilChanged(),
tap(() => this.peopleLoading = true),
switchMap(term => this._nodeHTTPService.getUsers(term).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.peopleLoading = false)
))
)
);
console.log('this.people$: ', this.people$)
}
}
NodeHttpService:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { CdfServiceService } from "./cdf-service.service";
@Injectable({
providedIn: 'root'
})
export class NodeHTTPService {
constructor(private http: HttpClient, private _cdfServiceService: CdfServiceService) { }
getUsers(i) {
if (!i) { i = ''};
let users = this.http.get(`https://chq-smscqa01.chq.ei/db/users?user=${i}`)
return users;
}
}
非常感谢您对这个问题的任何意见!谢谢。
您可以立即做两件事来提高性能
1) 通过启用虚拟滚动实现 DOM 回收。
如documentation所述,您可以将virtualScroll
输入属性设置为true
,这样只会加载指定数量的DOM ] 元素,它基于 ng-select 下拉列表的当前滚动容器的高度。
2) 在服务器端实现分页。这将减少每个 HTTP 请求的负载,从而使其在前端和后端都更快。
您可以将 virtualScroll
添加到您的 <ng-select>
:
[virtualScroll]="true"