debounce
Delays a function call until wait has passed since the last call — only the trailing call in a burst survives.
Lecture
debounce wraps a callback so that repeated calls in quick
succession collapse into a single call. Every call restarts a timer of
length wait; the wrapped func only actually
fires once wait has passed without another call —
and it fires with whatever argument was passed in that last call. This is
the classic "wait for the user to stop typing before searching" pattern.
In JS, FxTS attaches a .cancel() method directly onto the
returned function. Dart functions can't carry extra members, so FxDart
returns a Debounced<T> instead — a class with a
call(T arg) method, which Dart lets you invoke with plain
function-call syntax (debounced(arg)) thanks to the
call() convention, plus an explicit .cancel() to
drop any pending invocation.
By default (leading: false), only the trailing
edge fires — the last call in a burst, after things go quiet. Pass
leading: true and the first call in a burst
fires immediately instead, with every call before the next quiet period
suppressed.
Demo 1 · Trailing edge (the default)
Three rapid calls collapse into one — only the last argument survives:
Demo 2 · Leading edge and cancel()
leading: true fires immediately and suppresses the rest of
the burst; .cancel() drops a pending trailing call entirely:
Method spelling
The callback carries the same thing as a method:
saveDraft.fxDebounce(wait) is
debounce(saveDraft, wait), named arguments and all.
void saveDraft(String text) => _post(text);
final save = saveDraft.fxDebounce(const Duration(milliseconds: 300));
save('h');
save('he');
save('hello'); // only this one reaches _post
The fx prefix is deliberate. It says which library is wrapping
the callback and leaves the bare name free for whatever else a project puts
on its function types — the same convention as the getter spellings in
fx.
Try it yourself
Exercise: wrap save in debounce (100ms wait)
so only the final value survives the burst of calls below.
On event streams
The same idea exists on the events layer: when the bursty thing is a
Stream rather than a callback,
fxEvents(s).debounce(window) emits the trailing value of
each burst once window has passed without a newer event —
and a value still pending when the stream closes is flushed, never
dropped. See fxEvents for the
chain this belongs to.
throttle — fires on a schedule instead of after quiet ·
delay & sleep — building timing demos ·
concurrent — rate-limiting for async pipelines ·
shuffle — seeded randomness