Ответ
Future.wait() — это статический метод класса Future, который позволяет параллельно запустить несколько асинхронных операций и дождаться результатов выполнения всех из них. Он принимает Iterable<Future> и возвращает Future<List<T>>, где T — это тип результата каждого из переданных Future.
Базовый пример:
Future<String> fetchUserProfile() async {
await Future.delayed(Duration(seconds: 1)); // Имитация сетевого запроса
return 'John Doe';
}
Future<int> fetchUserScore() async {
await Future.delayed(Duration(seconds: 2));
return 95;
}
Future<void> main() async {
// Запускаем оба Future параллельно. Общее время ~2 сек, а не 3.
final List<dynamic> results = await Future.wait([
fetchUserProfile(),
fetchUserScore(),
]);
print('Profile: ${results[0]}, Score: ${results[1]}');
// Вывод через ~2 секунды: Profile: John Doe, Score: 95
}
Ключевое поведение и обработка ошибок:
- Параллельное выполнение: Все Future в списке начинают выполняться немедленно, а не последовательно.
- Завершение: Возвращаемый Future завершится только когда завершатся все переданные Future.
- Ошибки: Если любой из Future завершится с ошибкой, то весь
Future.waitнемедленно завершится с этой ошибкой, и результаты остальных Future будут потеряны.// ❌ Проблема: если fetchUserProfile упадёт, мы не получим даже успешный результат fetchUserScore. try { final results = await Future.wait([fetchUserProfile(), fetchUserScore()]); } catch (e) { print('Один из запросов упал: $e'); }
Практические сценарии использования во Flutter:
-
Параллельная загрузка данных для экрана:
Future<void> loadInitialData() async { // Параллельно загружаем пользователя, настройки и список друзей final results = await Future.wait([ _userRepository.getCurrentUser(), _settingsRepository.fetchSettings(), _friendsRepository.getFriendList(), ]); setState(() { _currentUser = results[0] as User; _settings = results[1] as AppSettings; _friends = results[2] as List<Friend>; }); } -
Надёжная обработка ошибок с
try-catchдля каждого Future:Future<void> loadDataSafely() async { // Создаём Future, которые никогда не падают, а возвращают Result объект final futures = [ _fetchData1().then((value) => Result.success(value)).catchError((e) => Result.failure(e)), _fetchData2().then((value) => Result.success(value)).catchError((e) => Result.failure(e)), ]; final List<Result> results = await Future.wait(futures); // Теперь можем обработать успешные и неуспешные результаты независимо for (final result in results) { if (result.isSuccess) { print('Данные: ${result.value}'); } else { print('Ошибка загрузки: ${result.error}'); } } } -
Отправка нескольких независимых аналитических событий:
Future<void> logAnalyticsEvents() async { // Нам не важен результат, и мы не хотим ждать. Используем wait в isolate. unawaited(Future.wait([ _analytics.logEvent('screen_opened'), _analytics.logEvent('user_action', params: {'action': 'click'}), ])); }
Альтернатива для независимой обработки ошибок: Если нужно, чтобы каждый Future завершился независимо, и вы могли обработать все результаты и ошибки, рассмотрите использование Future.forEach с индивидуальным try-catch внутри цикла или пакет async с функцией FutureGroup.