如何阻止去抖动的Rxjs Observable?

时间:2019-11-21 11:49:00

标签: javascript angular rxjs

我创建了一个可观察对象,它将在进行最后更改后3秒触发,并调用服务的publishChange。它可以工作,但是我想创建一个doImmediateChange函数,该函数立即调用publishChange并停止去抖动的可观察对象。那怎么可能?

我的组件

class MyComponent {
    private updateSubject = new Subject<string>();

    ngOnInit() {
        this.updateSubject.pipe(
            debounceTime(3000),
            distinctUntilChanged()
        ).subscribe(val => {
            this.srv.publishChange(val);
        });
    }

    doChange(val: string) {
        this.updateSubject.next(val);
    }

    doImmediateChange(val: string) {

        // Stop the current updateSubject if debounce is in progress and call publish immediately
        // ??
        this.srv.publishChange(val);

    }

}

5 个答案:

答案 0 :(得分:7)

您可以使用debounceTimeswitchMap模拟delay。然后使用takeUntil取消内部的Observable,以防止发出等待值。

private updateSubject = new Subject<string>();
private interrupt = new Subject();

ngOnInit() {
  this.updateSubject.pipe(
    switchMap(val => of(val).pipe(
      delay(3000),
      takeUntil(this.interrupt)
    ))
  ).subscribe(val => publish(val));
}

doChange(val: string) {
  this.updateSubject.next(val);
}

doImmediateChange(val: string) {
  this.interrupt.next();
  publish(val);
}

https://stackblitz.com/edit/rxjs-ya93fb

答案 1 :(得分:1)

使用race operator

第一个完成的可观察对象将成为已预订的,因此此递归函数将在发出take(1)之后完成,然后重新订阅() => this.raceRecursive()

private timed$ = new Subject<string>();
private event$ = new Subject<string>();

ngOnInit() {
  this.raceRecursive()
}

raceRecursive() {
  race(
    this.timed$.pipe(debounceTime(1000)),
    this.event$
  )
    .pipe(take(1)) // force it to complete
    .subscribe(
      val => console.log(val), // srv call here
      err => console.error(err),
      () => this.raceRecursive() // reset it once complete
    )
}

doChange(val: string) {
  this.timed$.next(val)
}

doImmediateChange(val: string) {
  this.event$.next(val)
}

答案 2 :(得分:1)

您可以使用debouncerace实现此行为:
加上您提供的代码

private destroy$ = new Subject<void>();
private immediate$ = new Subject<void>();
private updateSubject$ = new Subject<string>();

constructor(private srv: PubSubService) {}

ngOnInit() {
  this.updateSubject$.pipe(
      takeUntil(this.destroy$),
      debounce(() => race(timer(3000), this.immediate$))
  ).subscribe(val => {
      this.srv.publishChange(val);
  });
}

doChange(val: string, immediate?: boolean) {
  this.updateSubject$.next(val);
  if (immediate) this.immediate$.next();
}

// don't forget to unsubscribe
ngOnDestroy() {
  this.destroy$.next();
}

立即做出更改将取代之前的正常更改(被反跳3秒),而不会造成延迟(由于我们的种族可观察)。

这是工作中的example

答案 3 :(得分:1)

您可以为每个值提供特定于值的去抖动时间,并使用debouncetimer来动态更改值的去抖动时间。

private updateSubject = new Subject<{ value: any, debounceTime: number}>();

ngOnInit() {
  updateSubject.pipe(
    debounce(({ debounceTime }) => timer(debounceTime)),
    pluck('value')
  ).subscribe(val => publish(val));
}

doChange(value: string) {
  updateSubject.next({ value, debounceTime: 3000 });
}

doImmediateChange(value: string) {
  updateSubject.next({ value, debounceTime: 0 });
}

这不会直接停止去抖动的Observable,但让我们用零延迟发出一个新值来“覆盖”一个等待值。

https://stackblitz.com/edit/rxjs-j15zyq

(user733421似乎不想添加完整的解决方案,所以我扩展了方法)

答案 4 :(得分:0)

debounceTime的值仅在可观察的创建时间上评估一次。

要能够动态更新debounceTime,请将debounce与计时器一起使用,如下所示:

 debounce(()=>timer(this.debounceTime)),