搜索框输入时如何取消之前的HTTP请求并添加请求延迟
实现搜索输入延迟请求与取消未完成请求
核心思路
利用RxJS的操作符同时满足两个需求:
debounceTime:延迟发起请求,等待用户停止输入一段时间后再触发,避免频繁请求。switchMap:在新请求发起时自动取消之前未完成的HTTP请求,确保只处理最新的搜索结果。
修改后的组件代码(推荐用FormControl方案)
// header.component.ts import { Component, OnInit, OnDestroy } from '@angular/core'; import { FormControl } from '@angular/forms'; import { debounceTime, switchMap, filter } from 'rxjs/operators'; import { Subscription } from 'rxjs'; import { ProductService } from './product.service'; import { Product } from './product.model'; // 假设你有Product类型定义 @Component({ selector: 'app-header', template: `<input type="text" [formControl]="searchControl" placeholder="搜索产品..." />` }) export class HeaderComponent implements OnInit, OnDestroy { searchControl = new FormControl(); searchResult: Product[] = []; private searchSubscription?: Subscription; constructor(private productService: ProductService) {} ngOnInit() { this.searchSubscription = this.searchControl.valueChanges .pipe( // 过滤空输入或纯空格,避免无效请求 filter(query => query.trim().length > 0), // 延迟300ms,用户停止输入后才发起请求 debounceTime(300), // 新请求触发时取消之前未完成的请求 switchMap(query => this.productService.searchProducts(query)) ) .subscribe(res => { // 直接截取前5条结果,比修改数组length更安全 this.searchResult = res.slice(0, 5); console.log(res); }); } ngOnDestroy() { // 组件销毁时取消订阅,防止内存泄漏 this.searchSubscription?.unsubscribe(); } }
保留原键盘事件的方案
如果不想改用FormControl,可通过Subject处理事件流:
// header.component.ts import { Component, OnInit, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs'; import { debounceTime, switchMap, filter } from 'rxjs/operators'; import { Subscription } from 'rxjs'; import { ProductService } from './product.service'; import { Product } from './product.model'; @Component({ selector: 'app-header', template: `<input type="text" (keyup)="searchProduct($event)" placeholder="搜索产品..." />` }) export class HeaderComponent implements OnInit, OnDestroy { searchResult: Product[] = []; private searchSubject = new Subject<string>(); private searchSubscription?: Subscription; constructor(private productService: ProductService) {} ngOnInit() { this.searchSubscription = this.searchSubject.pipe( filter(query => query.trim().length > 0), debounceTime(300), switchMap(query => this.productService.searchProducts(query)) ).subscribe(res => { this.searchResult = res.slice(0, 5); console.log(res); }); } searchProduct(event: KeyboardEvent) { const { value } = event.target as HTMLInputElement; this.searchSubject.next(value); } ngOnDestroy() { this.searchSubscription?.unsubscribe(); this.searchSubject.complete(); } }
服务代码(仅修正拼写错误)
// product.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Product } from './product.model'; @Injectable({ providedIn: 'root' }) export class ProductService { constructor(private http: HttpClient) {} searchProducts(query: string) { // 修正类型拼写:Prodcut → Product return this.http.get<Product[]>(`http://localhost:3000/products?q=${query}`); } }
关键操作符说明
debounceTime(300):设置300毫秒的延迟,只有用户停止输入超过300ms,才会将查询值传递给下一个操作符,避免频繁触发请求。filter:过滤掉空字符串或纯空格的输入,减少无效的HTTP请求。switchMap:每当新的查询值进入流,会立即取消之前未完成的HTTP请求订阅(Angular的HttpClient会自动终止对应的请求),只保留最新的请求,确保页面展示的是最新的搜索结果。
内容的提问来源于stack exchange,提问作者Amar
相关产品推荐
相关产品推荐

