You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular实现函数防抖:500ms内重复调用终止前次执行

Angular实现搜索防抖(仅保留最后一次请求)

方案一:使用RxJS Subject + debounceTime(推荐,符合响应式编程风格)

原代码存在两个问题:一是输入时频繁触发请求,二是_initializeProjectList中获取uuid的异步逻辑可能导致dispatch时uuid为空。以下是优化后的防抖实现:

import { Subject } from 'rxjs';
import { debounceTime, takeUntil, switchMap, take } from 'rxjs/operators';

// 组件类内添加Subject用于接收搜索值
private searchSubject = new Subject<string>();

ngOnInit(): void {
  // 初始化防抖逻辑
  this.searchSubject.pipe(
    debounceTime(500), // 500ms内连续输入则忽略前次
    takeUntil(this._destroyed$), // 组件销毁时取消订阅
    switchMap((searchValue) => {
      this.searchValue = searchValue;
      // 先获取当前用户uuid,再触发请求
      return this._store.select(selectAuthUserSuccess).pipe(take(1));
    })
  ).subscribe((response: UserAuthorizations | null) => {
    const uuid = response?.uuid ?? '';
    this._fetchProjectList(uuid);
  });
}

// 重构请求逻辑为单独方法,避免重复订阅
private _fetchProjectList(uuid: string): void {
  this.loading = true; // 开始加载时设置状态
  const reqPayload: ProjectFleetListRequestModel = {
    limit: this.limit,
    offset: this.offset,
    filter: this.searchValue,
    isFavorite: this.isActive,
    userUuid: uuid
  };

  this._store.dispatch(Action.loadingProjectFleetListtPayload({ reqPayload }));
  
  // 订阅请求结果,用take(1)避免重复订阅内存泄漏
  this._store.select(selectProjectFleetListSuccess).pipe(
    take(1),
    takeUntil(this._destroyed$)
  ).subscribe((data) => {
    if (data?.response) {
      this.total = data.totalCount ?? 0;
      this.projectArray = data.response ?? [];
      this.loading = false;
    }
  });
}

onValueChange(value: string): void {
  // 仅向Subject推送新值,防抖逻辑在ngOnInit中处理
  this.searchSubject.next(value);
}

// 组件销毁时完成Subject
ngOnDestroy(): void {
  this._destroyed$.next();
  this._destroyed$.complete();
  this.searchSubject.complete();
}

方案二:手动维护定时器(适合快速改造)

如果不想引入RxJS Subject,可以手动通过定时器实现防抖:

private debounceTimer: number | null = null;

onValueChange(value: string): void {
  this.searchValue = value;
  
  // 清除之前的定时器,确保仅保留最后一次请求
  if (this.debounceTimer) {
    clearTimeout(this.debounceTimer);
  }
  
  // 设置新的500ms定时器
  this.debounceTimer = setTimeout(() => {
    this._initializeProjectList();
  }, 500);
}

// 组件销毁时清除定时器,避免内存泄漏
ngOnDestroy(): void {
  this._destroyed$.next();
  this._destroyed$.complete();
  if (this.debounceTimer) {
    clearTimeout(this.debounceTimer);
  }
}

// 优化_initializeProjectList中的uuid异步问题
private _initializeProjectList(): void {
  this.loading = true;
  this._store.select(selectAuthUserSuccess).pipe(
    take(1),
    takeUntil(this._destroyed$)
  ).subscribe((response: UserAuthorizations | null) => {
    const uuid = response?.uuid ?? '';
    const reqPayload: ProjectFleetListRequestModel = {
      limit: this.limit,
      offset: this.offset,
      filter: this.searchValue,
      isFavorite: this.isActive,
      userUuid: uuid
    };

    this._store.dispatch(Action.loadingProjectFleetListtPayload({ reqPayload }));
    
    this._store.select(selectProjectFleetListSuccess).pipe(
      take(1),
      takeUntil(this._destroyed$)
    ).subscribe((data) => {
      if (data?.response) {
        this.total = data.totalCount ?? 0;
        this.projectArray = data.response ?? [];
        this.loading = false;
      }
    });
  });
}

关键说明

  • 方案一使用RxJS的debounceTime能更优雅地处理异步流,同时通过switchMap解决了原代码中uuid获取的异步问题。
  • 两种方案都在组件销毁时清理订阅/定时器,避免内存泄漏。
  • 重构请求方法或优化原初始化逻辑,避免重复订阅Store导致的冗余请求和内存问题。

内容的提问来源于stack exchange,提问作者Noobmaster619

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:42:11