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>
}Задание
ЛегкоДавайте создадим погодный сервис, который имитирует получение данных о погоде из разных городов! Вы попрактикуетесь в использовании 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!'
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий