【问题标题】:Angular: How to debounce a function call with Observable.timer() and switchMap?Angular:如何使用 Observable.timer() 和 switchMap 去抖动函数调用?
【发布时间】:2018-02-02 12:58:27
【问题描述】:

这是我的方法:

  filter(value) {    
    this.backendCall(value)    
  }

我想在后端调用之间设置一个延迟,这样我的方法就不会在每次使用 Observable.timer() 和 switchMap 击键时被调用。

作为一个例子我有这个来自异步验证器的代码正是我想要的

export function createAsyncValidator(checkFn: (value: string) => Observable<Boolean>, errorMessage: string) {
    return (control: AbstractControl): Observable<ValidationErrors> => {
        return Observable.timer(500).switchMap(() => {
            return checkFn(control.value)
                .map(result => (result ? null : { [errorMessage]: true }));
        });
    }
}

...但我努力将其应用于我的方法。这是我尝试过的:

  filter(value) {
    Observable.timer(500).switchMap(() => {
      return Observable.of(value);
    }).subscribe(() => {
      console.log('filter', value);
      // this.backendCall(value)
    });
  }

确实应用了延迟,但记录了所有值。我期待 swithMap 取消订阅那些在延迟期间到达的 observables。 我错过了什么?

【问题讨论】:

    标签: angular observable


    【解决方案1】:

    在订阅 observable 之前使用 debounceTime

    在您的过滤器函数中发出一个带有该值的事件,并在订阅中添加 debounceTime。

    filter(value: ValueType) {
        this.filterSubject.next(value);
    }
    

    过时:

    ngOnInit() {
        this.filterSubject = new Subject<ValueType>();
        this.filterSubject.debounceTime(500).subscribe((value: ValueType) => {
            this.backendCall(value);
        });
    }
    

    较新的 Angular 版本:

    在较新的 Angular(或准确地说是 RxJS)版本中,您需要通过以下方式管道操作符:

    ngOnInit() {
        this.filterSubject = new Subject<ValueType>();
        this.filterSubject.pipe(debounceTime(500)).subscribe((value: ValueType) => {
            this.backendCall(value);
        });
    }
    

    【讨论】:

      【解决方案2】:

      首先我认为你只是错过了那里的 return 声明:

      filter(value) {
          -->return<-- Observable.timer(500).switchMap(() => {
            return Observable.of(value);
          }).subscribe(() => {
            console.log('filter', value);
            // this.backendCall(value)
          });
        }
      

      但我真的不明白你试图在这里提出的逻辑。

      在此评论后编辑:

      我希望后端调用仅在我完成输入时发生 (例如延迟一秒)。油门将发送我的第一个 立即击键到后端

      您可以简单地使用 debounceTime 运算符来实现此类行为。

      doc here

      所以如果你的 source 是一个输入,你可以这样使用它:

      <myFormControl>.valueChanges.debounceTime(500).flatMap(value => {
          return this.backendCall(value);
      }).subscribe();
      

      这样,backendCall 会在你停止输入 500ms 后被调用。

      【讨论】:

      • 我希望后端调用仅在我完成输入时发生(例如延迟一秒)。 Throttle 会立即将我的第一次击键发送到后端。
      • 添加return语句变化不大,所有击键都是延迟发送的。
      • 我认为您的第一个逻辑与延迟运算符的使用有关。它不能达到你想要的。它只会延迟对 backendCall 的调用及其延迟运算符的用途。
      • 我的第一个逻辑确实是歪的。在 filter 方法中,限制任何东西已经太晚了。它需要从外部加以限制。现在想起来,我觉得很傻:)还是谢谢
      猜你喜欢
      • 1970-01-01
      • 2015-11-10
      • 2017-04-27
      • 2016-07-31
      • 2021-11-21
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 2020-07-22
      相关资源
      最近更新 更多