run<T> method

Future<T?> run<T>(
  1. Future<T> action()
)

Implementation

Future<T?> run<T>(Future<T> Function() action) async {
  final startTime = DateTime.now();

  if (!enabled) {
    _debugLog('AsyncDebounce bypassed (disabled)');
    try {
      final result = await action();
      final executionTime = DateTime.now().difference(startTime);
      onMetrics?.call(executionTime, false);
      return result;
    } catch (e) {
      if (resetOnError) {
        _debugLog('Error occurred, state reset');
      }
      rethrow;
    }
  }

  _timer?.cancel();

  // Cancel previous pending call
  if (_pendingCompleter != null && !_pendingCompleter!.isCompleted) {
    _pendingCompleter!.complete(null);
    _debugLog('AsyncDebounce cancelled previous call');
    final cancelTime = DateTime.now().difference(startTime);
    onMetrics?.call(cancelTime, true);
  }

  final currentCallId = ++_latestCallId;
  final completer = Completer<T?>();
  _pendingCompleter = completer;

  _timer = _timerFactory.createTimer(duration, () async {
    try {
      if (currentCallId != _latestCallId) {
        if (!completer.isCompleted) {
          completer.complete(null);
          _debugLog('AsyncDebounce cancelled during wait');
        }
        return;
      }

      _debugLog('AsyncDebounce executing async action');
      try {
        final result = await action();
        if (currentCallId == _latestCallId && !completer.isCompleted) {
          final executionTime = DateTime.now().difference(startTime);
          _debugLog(
              'AsyncDebounce completed in ${executionTime.inMilliseconds}ms');
          onMetrics?.call(executionTime, false);
          completer.complete(result);
        } else if (!completer.isCompleted) {
          _debugLog('AsyncDebounce cancelled after execution');
          completer.complete(null);
        }
      } catch (e, stackTrace) {
        _debugLog('AsyncDebounce error: $e');
        if (resetOnError) {
          _debugLog('Resetting AsyncDebouncer state due to error');
          cancel();
        }
        if (!completer.isCompleted) {
          completer.completeError(e, stackTrace);
        }
      }
    } catch (e, stackTrace) {
      if (!completer.isCompleted) {
        completer.completeError(e, stackTrace);
      }
    } finally {
      if (_pendingCompleter == completer) {
        _pendingCompleter = null;
      }
    }
  });

  return completer.future;
}