0
votes

I am learning RXJS and have the following context:

Service:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, interval } from 'rxjs';
import { debounceTime, tap, debounce } from 'rxjs/operators';
 
@Injectable({ providedIn: 'root' })
export class SomeProvider {

  private counter: BehaviorSubject<number> = new BehaviorSubject(0);
  public counter$ = this.counter.asObservable() // .pipe(debounceTime(2000))

  constructor(
  ) {
    interval(1000).subscribe(value => {
      console.log(value);
      this.counter.next(value);
    })
  };

}

Component:

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { SomeProvider } from './some.service';

@Component({
  selector: 'hello',
  template: `<h1>{{ provider.counter$ | async }}</h1>`,
  styles: [`h1 { font-family: Lato; }`],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HelloComponent  {

  constructor(public provider: SomeProvider) {

  }
}

Here is the stackblitz: https://stackblitz.com/edit/angular-ivy-cdvwnj

So question - right now the component updates counter in the component's template every second. I would like to simply debounce it using debounceTime. I thought it will be as easy as adding a pipe to Observable with debounceTime operator. But if I uncomment that change - counter is not even there.

Question:

  • how to apply debounceTime in this scenario correctly
  • why if we add pipe with debounceTime async pipe inside the template stops working (and requires additional change detection)?
3

3 Answers

1
votes

Instead of rewriting what is already written in docs, lets try to understand in simple layman language.

debounceTime() - It is a RxJs operator which listen for all the incoming data-stream for a given time-limit and only forwards the last one.

Example :-

MyAwesomeObservable().pipe(debounceTime(10000))

This means that debouncetime will not forward data-stream until 10secs elapsed. During that 10secs, if some new data-stream comes, debounceTime will again starts waiting for 10secs.

Your-Case :-

Since interval(1000) passes data every 1sec, debounceTime(2000) wait of 2sec never ends.

interval > debouncetime ,than your code will work.

1
votes

From the documentation

Emits a value from the source Observable only after a particular time span has passed without another source emission.

This will work if the time passed to the debounceTime < time passed to interval

Demo

1
votes

Like the other answers mentioned, because your debounceTime is higher than the interval(), it will cause all interval emissions to be 'debounced'.

If you want to debounce an interval to only emit every 2 seconds, instead of 1 second, and you don't have control over the interval time, you can use a filter:

public counter$ = this.counter.asObservable().pipe(
  filter((idx) => !(idx % 2))
)

This will make your counter emit only at even emissions.

see here