Published 2026-06-02
Private port of rate_limit: 0.1.0 that was abandoned.
HH.
Enforces a wait period between events.
// Avoid excessively updating the position while scrolling.
window.onScroll
.transform(HHThrottler(const Duration(milliseconds: 100)))
.forEach(updatePosition);
// Execute `renewToken` on click, but not more than once every 5 minutes.
querySelector('.interactive').onClick
.transform(HHThrottler(const Duration(minutes: 5), trailing: false))
.forEach(renewToken);
Enforces a quiet wait period between events.
// Avoid costly calculations while the window size is in flux.
window.onResize
.transform(HHDebouncer(const Duration(milliseconds: 150)))
.forEach(calculateLayout);
// Execute `sendMail` on click, debouncing subsequent calls.
querySelector('#postbox').onClick
.transform(new Debouncer(const Duration(milliseconds: 300), leading: true, trailing: false))
.forEach(sendMail);
// Ensure `batchLog` is executed once after 1 second of debounced calls.
var source = EventSource('/stream');
source.onMessage
.transform(HHDebouncer(const Duration(milliseconds: 250), maxWait: const Duration(seconds: 1)))
.forEach(batchLog);
HHDebouncer: output stream now correctly closes when cancelOnError: true and an error arrives. Previously the source subscription was auto-cancelled by Dart (which does not trigger onDone), leaving the output StreamController open indefinitely so downstream listeners never received onDone.HHDebouncer: cancelling a subscription no longer leaves pending waitTimer / maxWaitTimer running. The onCancel handler now calls cancelTimers() first, preventing ghost afterWait() callbacks from buffering events into a dead controller after cancellation.HHThrottler._debounce is now final (was late); it is assigned directly in the initializer list, restoring Dart's compile-time definite-assignment guarantee.HHThrottler: removed the redundant !leading && !trailing guard — HHDebouncer already performs and owns this validation.HHDebouncer: the intermediate _transformer getter was removed; the StreamTransformer factory is now constructed inline inside bind(), eliminating an unnecessary object allocation per call.HHDebouncer and HHThrottler: tests are now organized into named sub-groups (constructor, trailing-only, leading-only, leading and trailing, maxWait, stream lifecycle, cast) covering edge cases for burst detection, timer cancellation, stream closure, error forwarding, and cancelOnError semantics.