Is there a simple way to make debounceTime instant on the first value?
searchQueries.pipe(debounceTime(1000))
let's say i'm debouncing search queries to 1 second.
My understanding is that this will cause a 1 second delay on the first search, But, I want the first search query to be instant.
(e.g. in this example https://stackblitz.com/edit/typescript-adheqt?file=index.ts&devtoolsheight=50 if i type 123 quickly, it will only log 123, but i want it to log 1 and then log 123)
i could try something like
merge(searchQueries.pipe(first()),searchQueries.pipe(debounceTime(1000)))
but then that would potentially add a delay to a second search but is probably good enough.
Is there a way of configuring debounceTime that i'm missing? or should I potentially be using throttle or something else?
debounceTime delays the values emitted by a source for the given due time. If within this time a new value arrives, the previous pending value is dropped and the timer is reset. In this way debounceTime keeps track of most recent value and emits that most recent value when the given due time is passed.
The Debounce Time is the interval that must pass before a second pressing of a key is accepted. You can set this interval with the "Debounce time (sec)" slider. (See Figure B-4.) This delay can range from zero to five seconds. Previous: Turning BounceKeys On and Off.
debounceTimelinkEmits a notification from the source Observable only after a particular time span has passed without another source emission.
You could use multicast
or maybe even throttleTime
:
searchQueries.pipe(
multicast(new Subject(), s => merge(
s.pipe(take(1)),
s.pipe(skip(1), debounceTime(1000)),
)),
);
Since RxJS 6 the throttleTime
operator accepts a config parameter where you can tell it to emit both leading and trailing emissions. Maybe this will do what you want instead of debounceTime
.
searchQueries.pipe(
throttleTime(1000, undefined, { leading: true, trailing: true }),
);
Here's my 2 cents / an answer I modified from another post with java-ngrx.
dbounce-time-after.ts
import { OperatorFunction, SchedulerLike, concat } from "rxjs";
import { async } from "rxjs/internal/scheduler/async";
import { debounceTime, publish, take } from "rxjs/operators";
export function debounceTimeAfter(
amount: number,
dueTime: number,
scheduler: SchedulerLike = async,
): OperatorFunction<number, number> {
return publish(value =>
concat(
value.pipe(take(amount)),
value.pipe(debounceTime(dueTime, scheduler))),
)
);
}
export function debounceTimeAfterFirst(
dueTime: number,
scheduler: SchedulerLike = async,
): OperatorFunction<number, number> {
return debounceTimeAfter(1, dueTime, scheduler);
}
example.ts
of(1, 2, 3, 4, 5)
.pipe(
tap(value => console.log("TAP", value)),
debounceTimeAfterFirst(50)
)
.subscribe(value => console.log(value));
console
TAP 1
1
TAP 2
TAP 3
TAP 4
TAP 5
5
But you could also start debouncing after n
number of emits with debounceTimeAfter
.
It's more flexible to use debounce instead of debounceTime.
searchQueries.pipe(debounceTime(1000))
is equal to:
searchQueries.pipe(debounce(() => timer(1000))
You can create your own heuristic to determine what timeout needs to be used. For example:
searchQueries.pipe(debounce(() => timer(getTimeout()))
...
const getTimeout = () => {
return iterations === 1 ? 0 : 1000;
};
In that scenario you need to track the iterations count on your own and increase it with each value but there are many ways to do it without messing a lot with the code. I simply created a wrapped observable object that contains the original observable and the counting logic. Something like this:
export default class ObservableWrapper {
...
next(parameters) {
this.iterations++;
this.observable.next(parameters);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With