top | item 44821900

(no title)

achou | 6 months 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.

discuss

order

demetris|6 months ago

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).

yurishimo|6 months ago

Sad that the `scrollend` event isn't supported by Safari and doesn't look to be a part of their release this fall either.

cnity|6 months ago

Reactive 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

ffsm8|6 months ago

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

joeframbach|6 months ago

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.

ricardobeat|6 months ago

If I understand it correctly, they're saying the debounce function itself usually implements memoization in a way that will return you stale promises.

pas|6 months ago

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!

tossandthrow|6 months ago

Damn, 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.

ncr100|6 months ago

So - events / handlers may need to be tagged as "for human interaction"? (to avoid over-filtering signals?)

ignoramous|6 months ago

Such stuff has first-class support in Kotlin: Structured concurrency simplifies multi-threaded programming pretty effectively.