Menu
Coddy logo textTech

Futures и async/await

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 76 из 110.

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

Future — это своего рода обещание: «Я предоставлю вам результат, когда он будет готов». Вы можете создать его с помощью Future.delayed(), чтобы имитировать операцию, требующую времени:

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Для работы с результатом Future используйте async и await. Пометьте свою функцию как async, затем используйте await, чтобы приостановить выполнение до завершения Future:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Без await вы получите Future<String> вместо самой строки. Ключевое слово await распаковывает Future и возвращает значение внутри него. Обратите внимание, что любая функция, использующая await, должна быть помечена как async, и она автоматически возвращает Future.

Вы также можете возвращать значения напрямую из асинхронных функций — Dart автоматически оборачивает их в Future:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // Автоматически оборачивается в Future<int>
}
challenge icon

Задание

Легко

Давайте создадим погодный сервис, который имитирует получение данных о погоде из разных городов! Вы попрактикуетесь в использовании Future, async и await для обработки операций, выполнение которых занимает определенное время.

Вы организуете свой код в двух файлах:

  • weather_service.dart: Создайте класс WeatherService, который имитирует получение информации о погоде. Ваш класс должен содержать:
    • Метод fetchTemperature(String city), который возвращает Future<int>. Используйте Future.delayed() с задержкой в 100 миллисекунд для имитации сетевой задержки. Метод должен возвращать температуру на основе названия города: верните длину названия города, умноженную на 3.
    • Метод fetchCondition(String city), который возвращает Future<String>. Используйте Future.delayed() с задержкой в 100 миллисекунд. Верните 'Sunny', если название города содержит четное количество символов, в противном случае верните 'Cloudy'.
    • Асинхронный метод getFullReport(String city), который возвращает Future<String>. Этот метод должен ожидать (await) выполнения как fetchTemperature, так и fetchCondition, а затем возвращать отформатированную строку: '[city]: [temperature]C, [condition]'
  • main.dart: Импортируйте ваш погодный сервис и продемонстрируйте, как работают асинхронные операции. Ваша функция main должна быть асинхронной и:
    • Создавать экземпляр WeatherService
    • Выводить в консоль 'Fetching weather data...'
    • Ожидать (await) и выводить полный отчет для 'Paris'
    • Ожидать (await) и выводить полный отчет для 'Tokyo'
    • Ожидать (await) и выводить полный отчет для 'London'
    • Выводить в консоль 'Done!'

Обратите внимание, как каждый вызов getFullReport ожидает получения и температуры, и погодных условий перед возвратом комбинированного результата. Ключевое слово await приостанавливает выполнение до тех пор, пока каждый Future не завершится!

Ожидаемый результат:

Fetching weather data...
Paris: 15C, Cloudy
Tokyo: 15C, Cloudy
London: 18C, Sunny
Done!

Шпаргалка

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

Создайте Future с помощью Future.delayed():

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Используйте async и await для работы с объектами Future. Пометьте функцию как async и используйте await, чтобы приостановить выполнение до завершения Future:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

Ключевое слово await «распаковывает» Future и возвращает фактическое значение. Без него вы бы получили Future<String> вместо строки.

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

Возвращаемые значения из асинхронных функций автоматически оборачиваются в Future:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // Автоматически оборачивается в Future<int>
}

Попробуйте сами

import 'weather_service.dart';

Future<void> main() async {
  // TODO: Создайте экземпляр WeatherService
  
  // TODO: Выведите 'Fetching weather data...'
  
  // TODO: Дождитесь и выведите полный отчет для 'Paris'
  
  // TODO: Дождитесь и выведите полный отчет для 'Tokyo'
  
  // TODO: Дождитесь и выведите полный отчет для 'London'
  
  // TODO: Выведите 'Done!'
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование