One thing to watch out for when using debounce/throttle is the poor interaction with async functions. Debounced/throttled async functions can easily lead to unexpected behavior because they typically return the last result they have when the function is called, which would be a previous Promise for an async function. You can get a result that appears to violate causality, because the result of the promise returned by the debounce/throttle will (in a typical implementation) be from a prior invocation that happened before your debounce/throttle call.
There are async-safe variants but the typical lodash-style implementations are not. If you want the semantics of "return a promise when the function is actually invoked and resolve it when the underlying async function resolves", you'll have to carefully vet if the implementation actually does that.
Another thing to watch for is whether you actually need debouncing.
For example, debouncing is often recommended for handlers of the resize event, but, in most cases, it is not needed for handlers of observations coming from ResizeObserver.
I think this is the case for other modern APIs as well. I know that, for example, you don’t need debouncing for the relatively new scrollend event (it does the debouncing on its own).
Debouncing correctly is still super hard, even with rxjs.
There are always countless edge cases that behave incorrectly - it might not be important and can be ignored, but while the general idea of debouncing sounds easy - and adding it to an rxjs observable is indeed straightforward...
Actually getting the desired behavior done via rxjs gets complicated super fast if you're required to be correct/spec compliant
Not really, but I feel like you might've misunderstood me.
The debouncing of rxjs just takes an observation and debounces, which is essentially throttle with inverted output (it outputs last instead of first).
That's almost never what the product owner actually wants, at least IME.
If they give you any kind of soec, you'll quickly realize that limit.
I.e. debouncing after the request happened is impossible, just like cleanly abortion requests on exit or similar.
There are also often a ton of signals you need to add to the observale for all the events the PO wants to respond to, such as opening dialogues, interacting with elements outside of the context of the debounces event chain etc pp
It just keeps getting more complicated with every additional thing they come up with. But if they're fine with just living with the technical limitations, all is fine.
That doesn't sound correct. An async function ought to return a _new_ Promise on each invocation, and each of those returned Promises are independent. Are you conflating memoization? Memoized functions will have these problems with denouncing, but not your standard async function.
this sounds interesting but it's a bit too early here for me. by any chance can we (not simply a royal we :D) ask you to provide a code example (of a correct implementation), or a link to one? many thanks!
There are async-safe variants but the typical lodash-style implementations are not. If you want the semantics of "return a promise when the function is actually invoked and resolve it when the underlying async function resolves", you'll have to carefully vet if the implementation actually does that.