flutter_debounce_throttle

pub package License: MIT Tests Coverage

The Traffic Control System for Flutter Apps

Stop using manual Timers. They cause memory leaks and crashes.

All-in-one package for debounce, throttle, rate limiting, and async concurrency control. Memory-safe, lifecycle-aware, and works with any state management solution.

// One widget. Prevents double-tap payment bugs forever.
ThrottledInkWell(
  duration: 500.ms,
  onTap: () => processPayment(),
  child: Text('Pay \$99'),
)

Why Not Just Use easy_debounce?

Capability This Package easy_debounce Manual Timer
Memory Safe (Auto-dispose) ❌ Leaky
Async & Future Support
Race Condition Control ✅ 4 modes
Ready-to-use Widgets
State Management Mixin
Loading States Built-in

How It Works — Visualized

Throttle vs Debounce (Duration: 300ms)

➤ Throttle (Button Clicks)

Executes immediately, then locks for the duration. Subsequent events are ignored.

Events:    (Click1)    (Click2)    (Click3)              (Click4)
Time:      |─ 0ms ─────── 100ms ──── 200ms ──── 300ms ──── 400ms ──|
           ▼                                     ▲
Execution: [EXECUTE] ····················· [LOCKED/DROP] ······· [EXECUTE]
           └─────── 300ms cooldown ──────┘

Use: Payment buttons, save buttons, scroll handlers


➤ Debounce (Search Input)

Waits for a pause in events before executing.

Events:    (Type 'A')   (Type 'B')   (Type 'C')    [User stops typing]
Time:      |─ 0ms ──── 100ms ──── 200ms ────────────── 500ms ──────|
           ▼            ▼            ▼                  ▲
Execution: [WAIT] ····· [RESET] ····· [RESET] ········ [EXECUTE 'ABC']
                                      └─────── 300ms wait ──────┘

Use: Search autocomplete, form validation, window resize


Concurrency Modes (Async)

New task cancels the old one.

Task 1:  [──────── 500ms API Call ──X Cancelled
Task 2:              ↓ New search query
                     [──────── 500ms API Call ────────]  ✅ Result shown

Use: Search autocomplete, tab switching


Mode: drop (Default)

If busy, new tasks are ignored.

Task 1:  [──────── 500ms API Call ────────]  ✅ Completes
Task 2:            ↓ User taps again
                   [DROPPED ❌]

Use: Payment buttons, preventing double-tap


Mode: enqueue

Tasks queue and run in order.

Task 1:  [──────── 500ms ────────]  ✅
Task 2:            ↓ Queued
                   [Waiting...]      [──────── 500ms ────────]  ✅

Use: Chat messages, ordered operations


5-Second Start

Anti-Spam Button:

ThrottledInkWell(onTap: () => pay(), child: Text('Pay'))

Debounced Search:

final debouncer = Debouncer(duration: 300.ms);
TextField(onChanged: (s) => debouncer(() => search(s)))

That's it. No setup. No dispose. Auto-cleanup on widget unmount.


Widgets

Widget Use Case
ThrottledInkWell Button with ripple + throttle
ThrottledBuilder Custom throttled widget
DebouncedBuilder Custom debounced widget
DebouncedQueryBuilder Search with loading state
AsyncThrottledBuilder Async with lock
ConcurrentAsyncThrottledBuilder 4 concurrency modes
StreamDebounceListener Debounce stream events
StreamThrottleListener Throttle stream events

State Management Mixin

Works with Provider, Bloc, GetX, Riverpod, MobX — any ChangeNotifier:

class SearchController with ChangeNotifier, EventLimiterMixin {
  List<User> users = [];

  void onSearch(String text) {
    debounce('search', () async {
      users = await api.search(text);
      notifyListeners();
    });
  }

  @override
  void dispose() {
    cancelAll();  // Clean up all limiters
    super.dispose();
  }
}

Concurrency Modes

Handle race conditions with 4 strategies:

Mode Behavior Use Case
drop Ignore new while busy Payment buttons
replace Cancel old, run new Search autocomplete
enqueue Queue in order Chat messages
keepLatest Current + last only Auto-save
ConcurrentAsyncThrottledBuilder(
  mode: ConcurrencyMode.replace,  // Cancel stale requests
  builder: (context, throttle, isLoading, pendingCount) => ...
)

Installation

dependencies:
  flutter_debounce_throttle: ^1.1.0

v1.1.0 Features

// Duration extensions
ThrottledInkWell(duration: 500.ms, ...)

// Leading + trailing edge (like lodash)
Debouncer(leading: true, trailing: true)

// Rate limiter with Token Bucket
RateLimiter(maxTokens: 10, refillRate: 2)

// Queue backpressure control
ConcurrentAsyncThrottler(maxQueueSize: 10)

Quality Assurance

Guarantee How
360+ tests Comprehensive unit & integration tests
95% coverage All edge cases covered
Type-safe No dynamic, full generics
Memory-safe Zero leaks verified

Package Use When
dart_debounce_throttle Pure Dart (Server/CLI)
flutter_debounce_throttle_hooks Flutter + Hooks

GitHub · API Reference · Best Practices

Made with craftsmanship by Brewkits