import 'dart:async'; typedef _Debounceable<S, T> = Future<S?> Function(T parameter); class Debouncer { Debouncer(this._duration, this._callback); final Duration _duration; final dynamic _callback; late final _Debounceable<dynamic, String> _debouncedSearch = _debounce<dynamic, String>(_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<S, T> _debounce<S, T>(_Debounceable<S?, T> 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<void> _completer = Completer<void>(); void _onComplete() { _completer.complete(); } Future<void> 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(); }