throttle
Invokes a function at most once per wait period — on a schedule, unlike debounce's "wait for quiet."
Lecture
throttle guarantees func runs at most once every
wait, no matter how often the throttled function is called.
That's the key difference from debounce:
debounce keeps resetting its timer on every call, so a
continuous stream of calls can delay execution indefinitely; throttle's
window is fixed once it starts, so calls still get through on a regular
cadence — useful for things like scroll or resize handlers where you want
periodic updates, not just one at the very end.
Both leading and trailing default to
true: the first call in a window fires immediately (leading
edge), and if more calls arrive before the window closes, the
last of those fires once the window ends (trailing edge, with
the latest argument). Turn either off to get leading-only or
trailing-only behavior. Like debounce, the returned
Throttled<T> is a callable class with a
.cancel() to drop a pending trailing call.
Demo 1 · Leading + trailing (the default)
The first call fires immediately; the last call in the window fires again once the window closes:
Demo 2 · Tuning leading/trailing, and cancel()
Turn off leading for trailing-only behavior, off
trailing for leading-only, or call .cancel() to
drop a pending trailing call:
Method spelling
Same as debounce:
onScroll.fxThrottle(wait) is
throttle(onScroll, wait), and it forwards
leading and trailing unchanged.
void onScroll(double offset) => _measure(offset);
final handler = onScroll.fxThrottle(
const Duration(milliseconds: 100),
trailing: false,
);
The fx prefix names the library doing the wrapping, the same
convention as the getter spellings in
fx.
Try it yourself
Exercise: wrap onClick in throttle (100ms
wait) so rapid clicks register at most twice — leading and trailing —
instead of three separate times.
On event streams
The same idea exists on the events layer: when the chatty thing is a
Stream rather than a callback,
fxEvents(s).throttle(window, trailing: …) lets one event
per window through. One default differs: the stream form is
leading-only unless you pass trailing: true (the callback
wrapper above defaults both edges on). See
fxEvents for the chain this
belongs to.
debounce — waits for quiet instead of a fixed schedule ·
delay & sleep — building timing demos ·
shuffle — seeded randomness ·
concurrent — rate-limiting for async pipelines