Angular9 防抖优化

2020-07-06 15:36 更新

如果你需要发一个 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 中。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号