Angular9 防抖优化
如果你需要发一个 HTTP 请求来响应用户的输入,那么每次击键就发送一个请求的效率显然不高。最好等用户停止输入后再发送请求。这种技术叫做防抖。可以通过防抖来优化与服务器的交互。
考虑下面这个模板,它让用户输入一个搜索词来按名字查找 npm
包。 当用户在搜索框中输入名字时,PackageSearchComponent
就会把这个根据名字搜索包的请求发给 npm web API
。
Path:"app/package-search/package-search.component.html (search)" 。
<input (keyup)="search($event.target.value)" id="name" placeholder="Search"/>
<ul>
<li *ngFor="let package of packages$ | async">
<b>{{package.name}} v.{{package.version}}</b> -
<i>{{package.description}}</i>
</li>
</ul>
这里,keyup
事件绑定会把每次击键都发送给组件的 search()
方法。下面的代码片段使用 RxJS 的操作符为这个输入实现了防抖。
Path:"app/package-search/package-search.component.ts (excerpt)" 。
withRefresh = false;
packages$: Observable<NpmPackageInfo[]>;
private searchText$ = new Subject<string>();
search(packageName: string) {
this.searchText$.next(packageName);
}
ngOnInit() {
this.packages$ = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(packageName =>
this.searchService.search(packageName, this.withRefresh))
);
}
constructor(private searchService: PackageSearchService) { }
searchText$
是来自用户的搜索框值的序列。它被定义为 RxJS Subject 类型,这意味着它是一个多播 Observable
,它还可以通过调用 next(value)
来自行发出值,就像在 search()
方法中一样。
除了把每个 searchText 的值都直接转发给 PackageSearchService 之外,ngOnInit() 中的代码还通过下列三个操作符对这些搜索值进行管道处理,以便只有当它是一个新值并且用户已经停止输入时,要搜索的值才会抵达该服务。
debounceTime(500)
- 等待用户停止输入(本例中为 1/2 秒)。
distinctUntilChanged()
- 等待搜索文本发生变化。
switchMap()
- 将搜索请求发送到服务。
这些代码把 packages$
设置成了使用搜索结果组合出的 Observable
对象。 模板中使用 AsyncPipe
订阅了 packages$
,一旦搜索结果的值发回来了,就显示这些搜索结果。
使用 switchMap() 操作符
switchMap()
操作符接受一个返回 Observable
的函数型参数。在这个例子中,PackageSearchService.search
像其它数据服务方法那样返回一个 Observable
。如果先前的搜索请求仍在进行中 (如网络连接不良),它将取消该请求并发送新的请求。
请注意,switchMap()
会按照原始的请求顺序返回这些服务的响应,而不用关心服务器实际上是以乱序返回的它们。
如果你觉得将来会复用这些防抖逻辑, 可以把它移到单独的工具函数中,或者移到
PackageSearchService
中。
更多建议: