import 'dart:async'; typedef _Debounceable = Future Function(T parameter); class Debouncer { Debouncer(this._duration, this._callback); final Duration _duration; final dynamic _callback; late final _Debounceable _debouncedSearch = _debounce(_callback); /// Returns a new function that is a debounced version of the given function. /// /// This means that the original function will be called only after no calls /// have been made for the given Duration. _Debounceable _debounce(_Debounceable function) { _DebounceTimer? debounceTimer; return (T parameter) async { if (debounceTimer != null && !debounceTimer!.isCompleted) { debounceTimer!.cancel(); } debounceTimer = _DebounceTimer(_duration); try { await debounceTimer!.future; } on _CancelException { return null; } return function(parameter); }; } process(data) { return _debouncedSearch(data); } } // A wrapper around Timer used for debouncing. class _DebounceTimer { final Duration debounceDuration; _DebounceTimer( this.debounceDuration ) { _timer = Timer(debounceDuration, _onComplete); } late final Timer _timer; final Completer _completer = Completer(); void _onComplete() { _completer.complete(); } Future get future => _completer.future; bool get isCompleted => _completer.isCompleted; void cancel() { _timer.cancel(); _completer.completeError(const _CancelException()); } } // An exception indicating that the timer was canceled. class _CancelException implements Exception { const _CancelException(); }