Можно ли отменить Future в Dart?

«Можно ли отменить Future в Dart?» — вопрос из категории Асинхронность, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Непосредственно отменить стандартный Future нельзя, так как он представляет собой уже запущенную асинхронную операцию. Однако можно реализовать логику отмены с помощью нескольких подходов.

1. Использование Completer для ручного управления:

Future<String> cancellableOperation(Duration delay) {
  final completer = Completer<String>();
  final timer = Timer(delay, () {
    if (!completer.isCompleted) {
      completer.complete('Operation completed');
    }
  });

  // Возвращаем future, который можно "отменить", завершив completer досрочно
  return completer.future.whenComplete(() => timer.cancel());
}

// Использование
final future = cancellableOperation(Duration(seconds: 5));
// Для "отмены" нужно где-то сохранить completer и вызвать completer.completeError('Cancelled')

2. Пакет async с CancelableOperation (рекомендуется):

import 'package:async/async.dart';

Future<void> main() async {
  final operation = CancelableOperation.fromFuture(
    Future.delayed(Duration(seconds: 5), () => 'Result'),
    onCancel: () => Future.value('Cancelled'),
  );

  // Отмена через 2 секунды
  Future.delayed(Duration(seconds: 2), () {
    operation.cancel();
    print('Operation cancelled');
  });

  try {
    final result = await operation.value;
    print(result);
  } catch (e) {
    print('Error: $e'); // CanceledException при отмене
  }
}

3. Для сетевых запросов используйте специализированные механизмы:

  • В dio: CancelToken
  • В http: закрытие клиента или использование Stream с таймаутами

Важно: Отмена Future не прерывает уже выполняющийся код (например, CPU-интенсивные вычисления), а только предотвращает обработку результата. Для реальной отмены длительных операций нужно периодически проверять флаг отмены.