Какие способы создания Future в Dart ты знаешь?

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

Ответ

В Dart Future представляет отложенное вычисление или асинхронную операцию. Я создаю их несколькими способами в зависимости от задачи.

1. Использование конструкторов класса Future

Это низкоуровневые конструкторы для ручного создания Future.

  • Future(): Обертывает синхронную или асинхронную операцию, выполняемую в event loop.

    Future<int> heavyCalculation() {
      return Future(() {
        // Имитация долгой синхронной операции
        int result = 0;
        for (int i = 0; i < 1000000000; i++) {
          result += i;
        }
        return result; // Будет обернуто в завершенный Future
      });
    }
  • Future.delayed(): Создает Future, который завершается с результатом функции после задержки. Часто используется для имитации сетевых запросов или таймеров.

    Future<String> fetchUserData() {
      return Future.delayed(
        const Duration(seconds: 2),
        () => '{"name": "John"}', // Эта функция выполнится через 2 секунды
      );
    }
  • Future.value(): Немедленно создает завершенный успешный Future с заданным значением. Полезно в тестах или для возврата кэшированных данных.

    Future<Config> loadConfig() {
      if (_cachedConfig != null) {
        return Future.value(_cachedConfig!); // Немедленный возврат
      }
      return _fetchFromNetwork();
    }
  • Future.error(): Немедленно создает завершенный Future с ошибкой.

    Future<void> validateLogin(String email) {
      if (!email.contains('@')) {
        return Future.error(FormatException('Invalid email'));
      }
      return _checkServer();
    }

2. Использование async/await

Любая функция, помеченная ключевым словом async, автоматически возвращает Future. Это самый частый способ в production-коде.

Future<List<Post>> fetchPosts() async {
  // `await` приостанавливает выполнение функции, но не потока.
  final response = await http.get(Uri.parse('https://api.example.com/posts'));
  if (response.statusCode == 200) {
    return (jsonDecode(response.body) as List).map((e) => Post.fromJson(e)).toList();
  } else {
    throw Exception('Failed to load posts');
  }
}
// Функция fetchPosts возвращает Future<List<Post>>

3. Преобразование Stream в Future

Методы first, last, single, elementAt и reduce у Stream возвращают Future.

Future<int> getFirstValueFromStream(Stream<int> stream) {
  return stream.first; // Возвращает Future<int>
}

Выбор способа: Для работы с внешними ресурсами (сеть, БД) я использую async-функции. Для создания отложенных задач или моков в тестах — конструкторы Future.delayed или Future.value.