7 ms·
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 une
by achou 1y ago
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.
- pas 1y agothis 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!
- tracker1 1y agoI would probably look at the lodash implementation (for JS/TS) as a complete implementation example. https://github.com/lodash/lodash/blob/8a26eb42adb303f4adc7ef56e300f14c5992aa68/lodash.js#L10372 https://github.com/lodash/lodash/blob/8a26eb42adb303f4adc7ef...
- cnity 1y agoReactive programming (such as with RxJS [0]) can be a good solution to this, since they provide primitives that understand time-based dependencies. [0]: https://rxjs.dev/api/index/function/switchMap https://rxjs.dev/api/index/function/switchMap
- ffsm8 1y agoDebouncing 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
- pas 1y agocan you recommend some reading about the topic? also maybe point to some specs that require (and describe?) fully correct debouncing? thanks!
- ffsm8 1y agoNot 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.
- demetris 1y agoAnother 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).
- tossandthrow 1y agoDamn, there was another thread not too long ago claiming that a sync does not mean concurrent - this would have been a great example to bring up.
- ignoramous 1y agoSuch stuff has first-class support in Kotlin: Structured concurrency simplifies multi-threaded programming pretty effectively.
- joeframbach 1y agoThat 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.
- ricardobeat 1y agoIf I understand it correctly, they're saying the debounce function itself usually implements memoization in a way that will return you stale promises.
- ncr100 1y agoSo - events / handlers may need to be tagged as "for human interaction"? (to avoid over-filtering signals?)