How to debounce an input while skipping the first entry
I was recently working on a task requiring filtering and sorting data on the frontend side. I came across an issue that I wanted to debounce user input in order to decrease a number of filter and sort operations, however initial operation should be performed as soon as possible (without debounce).

I was recently working on a task requiring filtering and sorting data on the frontend side. I came across an issue that I wanted to debounce user input in order to decrease a number of filter and sort operations, however initial operation should be performed as soon as possible (without debounce).
Let’s see how RxJS library helped me out!
Debounce every entry
Without the need for performing initial operation immediately, the solution might look like this:
import { of, BehaviorSubject, combineLatest } from 'rxjs';
import { debounceTime, delay, tap, map } from 'rxjs/operators';
class FrameworksService {
private querySubject = new BehaviorSubject<string>('');
private query$ = this.querySubject.pipe(
debounceTime(2000)
);
private collection$ = of([
'Angular',
'React',
'Vue'
]).pipe(
delay(10)
);
filteredCollection$ = combineLatest(
this.query$,
this.collection$
).pipe(
tap(() => console.log('filtering')),
map(([query, collection]) => collection.filter(item => item.includes(query)))
);
filter(query: string) {
this.querySubject.next(query);
}
}
const frameworksService = new FrameworksService();
frameworksService.filter('a');
frameworksService.filteredCollection$.subscribe(console.log);
setTimeout(() => {
frameworksService.filter('Angular');
frameworksService.filter('React');
frameworksService.filter('Vue');
frameworksService.filter('React');
}, 5000);
Note that, each entry is debounced, hence you need to wait 2s (debounce time) for the first console.log (a sign of performing filtering action) to appear.
However, I wanted to perform the initial operation ASAP.
Debounce every entry except for the first one
Here comes the power of RxJS operators.
I simply created two streams representing query, namely:
private querySubject = new BehaviorSubject<string>('');
private initialQuery$ = this.querySubject.pipe(
first()
);
private debouncedQuery$ = this.querySubject.pipe(
skip(1),
debounceTime(2000)
);
and combined them as follows:
private query$ = merge(
this.initialQuery$,
this.debouncedQuery$
);
The rest of the FrameworksService class remained unchanged.
With the above solution you will see the first console.log immediately, while further queries will be debounced.