← Назад к вопросам

Что такое async, await и Future в Dart?

1.6 Junior🔥 252 комментариев
#Dart#Асинхронность

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Async, Await и Future в Dart

Future — асинхронное значение

Future — это объект, который представляет будущее значение, которое может быть доступно со временем или вызвать ошибку:

// Future завершится одним из трёх состояний:
// 1. Успешно (resolved) с значением
// 2. Ошибка (rejected) с исключением
// 3. В ожидании (pending) — ещё не завершён

Future<String> fetchUserName() {
  // Эта функция вернёт значение через 2 секунды
  return Future.delayed(
    Duration(seconds: 2),
    () => "John Doe",
  );
}

// Использование Future
final future = fetchUserName();
// future содержит обещание получить имя позже

Обработка Future с .then()

fetchUserName().then((name) {
  print("User: $name");
}).catchError((error) {
  print("Error: $error");
}).whenComplete(() {
  print("Request finished");
});

// Цепочка операций
Future<int> getUserAge(String name) {
  return Future.delayed(
    Duration(seconds: 1),
    () => 30,
  );
}

fetchUserName()
  .then((name) => getUserAge(name))
  .then((age) => print("Age: $age"))
  .catchError((error) => print("Error: $error"));

async и await — читаемый синтаксис

async/await — это синтаксический сахар для работы с Future, делающий код выглядеть синхронным:

// ❌ Без async/await (callback hell)
fetchUserName().then((name) {
  getUserAge(name).then((age) {
    getAddress(age).then((address) {
      print("$name, $age, $address");
    }).catchError((e) => print("Error: $e"));
  }).catchError((e) => print("Error: $e"));
}).catchError((e) => print("Error: $e"));

// ✅ С async/await (читаемо)
Future<void> getUserInfo() async {
  try {
    final name = await fetchUserName();
    final age = await getUserAge(name);
    final address = await getAddress(age);
    print("$name, $age, $address");
  } catch (e) {
    print("Error: $e");
  }
}

// Вызов
await getUserInfo();

Как работает async?

// Функция с async автоматически возвращает Future
async void sayHello() async {
  print("Hello"); // Выполнится синхронно
  await Future.delayed(Duration(seconds: 1));
  print("World"); // Выполнится через 1 секунду
}

// Это эквивалентно:
Future<void> sayHello() {
  print("Hello");
  return Future.delayed(Duration(seconds: 1))
    .then((_) => print("World"));
}

// Вызов async функции
await sayHello(); // Ждёт завершения
sayHello(); // Не ждёт, просто запускает

Future — примеры из реальной жизни

// HTTP запрос
Future<User> fetchUser(int id) async {
  final response = await http.get(
    Uri.parse("https://api.example.com/users/$id"),
  );

  if (response.statusCode == 200) {
    return User.fromJson(jsonDecode(response.body));
  } else {
    throw Exception("Failed to load user");
  }
}

// Чтение файла
Future<String> readFile(String path) async {
  final file = File(path);
  return await file.readAsString();
}

// Задержка (для тестирования)
Future<void> delayedPrint(String message) async {
  await Future.delayed(Duration(seconds: 2));
  print(message);
}

// Использование
final user = await fetchUser(1);
final content = await readFile("file.txt");
await delayedPrint("Done!");

Parallel выполнение с Future.wait()

// Выполнить несколько Future одновременно
Future<List<dynamic>> getMultipleData() async {
  try {
    final results = await Future.wait([
      fetchUser(1),
      fetchUser(2),
      fetchUser(3),
    ]);
    // results содержит результаты всех трёх запросов
    return results;
  } catch (e) {
    print("Error: $e");
  }
}

// Альтернатива с именованными переменными
Future<void> getMultipleDataNamed() async {
  try {
    final [user1, user2, user3] = await Future.wait([
      fetchUser(1),
      fetchUser(2),
      fetchUser(3),
    ]);
    print("$user1, $user2, $user3");
  } catch (e) {
    print("Error: $e");
  }
}

Обработка ошибок в async функциях

// Try-catch для одной операции
async Future<void> safeFetch() async {
  try {
    final user = await fetchUser(1);
    print(user);
  } on SocketException catch (e) {
    print("Network error: $e");
  } on FormatException catch (e) {
    print("Parse error: $e");
  } catch (e) {
    print("Unknown error: $e");
  } finally {
    print("Cleanup");
  }
}

// Обработка одной ошибки из множества Future
Future<void> handleMultipleErrors() async {
  try {
    await Future.wait([
      fetchUser(1),
      fetchUser(999), // Ошибка
      fetchUser(3),
    ]);
  } catch (e) {
    // Прерывается при первой ошибке
    print("One failed: $e");
  }
}

// Продолжить несмотря на ошибки
Future<void> handleAllErrors() async {
  final results = await Future.wait(
    [
      fetchUser(1),
      fetchUser(999),
      fetchUser(3),
    ],
    eagerError: false, // Не прерывать при ошибке
  );
  print(results); // Содержит успехи и ошибки
}

Timeout для Future

// Добавить таймаут
Future<User> fetchUserWithTimeout(int id) async {
  try {
    final user = await fetchUser(id).timeout(
      Duration(seconds: 5),
      onTimeout: () => throw TimeoutException(
        "Request took too long",
      ),
    );
    return user;
  } catch (e) {
    print("Error: $e");
    rethrow;
  }
}

// Альтернатива
Future<User?> fetchUserOrNull(int id) async {
  try {
    return await fetchUser(id).timeout(
      Duration(seconds: 5),
      onTimeout: () => null,
    );
  } catch (e) {
    return null;
  }
}

Stream — последовательность значений

Stream похож на Future, но вместо одного значения возвращает несколько значений со временем:

// Future — одно значение
Future<int> getNumber() async {
  await Future.delayed(Duration(seconds: 1));
  return 42;
}

// Stream — несколько значений
Stream<int> getNumbers() async* {
  for (int i = 1; i <= 5; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i; // Вернуть значение
  }
}

// Использование Stream
await for (final number in getNumbers()) {
  print(number); // Печатает 1, затем 2, затем 3...
}

// Или с listen
getNumbers().listen(
  (number) => print(number),
  onError: (e) => print("Error: $e"),
  onDone: () => print("Finished"),
);

Сравнение: Future vs Stream

ХарактеристикаFutureStream
Значения1Много
ВремяОдин разНесколько раз
ЗавершениеОбязательноОпционально
ПримерHTTP запросWebSocket, Timer

Best Practices

  • Предпочитайте async/await вместо .then()
  • Используйте try-catch для обработки ошибок
  • Future.wait() для параллельного выполнения
  • Не забывайте await перед Future
  • Используйте Stream для потока данных
  • Добавляйте timeout для сетевых запросов

Итог

  • Future — асинхронное значение с одним результатом
  • async — ключевое слово для async функций
  • await — ожидание Future (только в async функциях)
  • Stream — последовательность значений
  • Это основа асинхронного программирования во Flutter