订阅 FormBuilder valueChanges 时,使用 debounceTime 和 distinctUntilChanged 不起作用

Using debounceTime & distinctUntilChanged is not working when subscribing to FormBuilder valueChanges

非常简单地说,我想在用户停止输入一定时间后执行查询。我看到的每个使用 FormBuilder 的教程都建议订阅输入字段的 valueChanges,同时管道 debounceTimedistinctUntilChanged

this.threadForm.get('body').valueChanges.pipe(
            debounceTime(500),
            distinctUntilChanged(),
            mergeMap(search => this.db.query$(...)`))
      )

我无法让它正常工作。它似乎可以正确地对时间进行去抖动,但是当它通过管道传输时,它会发送多个最终结果(distinctUntilChanged 应该处理)。我做错了什么?

这是问题的快速视频(我添加了一个 tap 所以你可以看到网页正在记录几个最终结果):

https://streamable.com/h2him

谢谢!

编辑:添加周围代码 source 函数在每次按键时也是 运行 所以我认为我正在实例化多个可观察对象我的去抖动。如何在其中添加去抖动逻辑?

  source: (searchTerm, renderList) => {
    //searchTerm is triggered on every button click
    if (searchTerm.length === 0) {
      renderList(this.mentions, searchTerm)
    } else {
      //are multiple instances of this observable being made??
      this.threadForm.get('body').valueChanges.pipe(
        distinctUntilChanged(),
        debounceTime(500),
        tap(x => console.log(x)),
        switchMap(search => this.db.query$(`user/collection?like=username_${searchTerm}&limit=5`))
      ).subscribe( x => {
        console.log(x)
      });
    }
  },

试试这个:

this.threadForm.get('body').valueChanges.pipe(
  debounceTime(1000), 
  distinctUntilChanged()).subscribe(changes => {
  this.db.query$(...)
});

我很确定这里的问题与 valueChanges 发出的对象有关。对于 distinctUntilChanged 发出的对象不同,您可能希望先将此对象映射到您实际需要的值。 (您也可以将回调传递给 distinctUntilChanged 以控制要区分的内容)

例如

this.threadForm.get('body').valueChanges.pipe(
  debounceTime(500),
  map( (obj) => obj.searchVal ),
  distinctUntilChanged(),
  mergeMap(search => this.db.query$(...)`))
)

而且您肯定在寻找 switchMap 而不是 mergeMap

编辑

为了使用源函数,您可以像这样使用主题。

var searchSubject = new Subject<any>();

source: (searchTerm, renderList) => {
  searchSubject.next({searchTerm, renderList});
}

比这个 searchSubject 您仅在 ngOnInit 中订阅一次并在 onDestroy 函数中取消订阅。

searchSubject.pipe(
 debounceTime(500),
 distinctUntilChanged(),
 mergeMap(search => this.db.query$(...)`))
)