Что такое Dart Futures и как использовать async/await?
Future<T> представляет результат асинхронной операции; async/await — синтаксический сахар, позволяющий писать асинхронный код линейно, не блокируя однопоточный event loop Dart.
Что такое Future в Dart
Future<T> — объект из dart:async, представляющий результат асинхронной операции, который будет доступен в будущем. Future находится в одном из трёх состояний: uncompleted, completed with value, completed with error. Dart использует однопоточный event loop с двумя очередями: event queue (I/O, таймеры) и microtask queue (Future.value, scheduleMicrotask). Microtask-очередь всегда опустошается перед следующим событием из event queue.
async/await — синтаксический сахар над Future
Функция с модификатором async автоматически возвращает Future<T>. Ключевое слово await приостанавливает выполнение функции до завершения Future, не блокируя event loop — в этот момент могут выполняться другие задачи из очередей.
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
// Простой пример: цепочка Future через async/await
Future<Map<String, dynamic>> fetchUser(int id) async {
final uri = Uri.parse('https://jsonplaceholder.typicode.com/users/$id');
final response = await http.get(uri);
if (response.statusCode != 200) {
throw Exception('HTTP ${response.statusCode}');
}
return jsonDecode(response.body) as Map<String, dynamic>;
}
// Параллельные Future через Future.wait
Future<void> loadAll() async {
// Последовательно: ~2 секунды
// final a = await fetchUser(1);
// final b = await fetchUser(2);
// Параллельно: ~1 секунда
final results = await Future.wait([
fetchUser(1),
fetchUser(2),
]);
print(results[0]['name']); // Leanne Graham
print(results[1]['name']); // Ervin Howell
}
// Обработка ошибок
Future<String> safeLoad(int id) async {
try {
final user = await fetchUser(id);
return user['name'] as String;
} on Exception catch (e) {
print('Error: $e');
return 'Unknown';
}
}
void main() async {
print(await safeLoad(1)); // Leanne Graham
await loadAll();
}
Полезные методы Future
Future.value(x)— Future, уже завершённый значением; callback вызывается в microtask очереди.Future.error(e)— Future с ошибкой.Future.delayed(duration, fn)— выполняет fn через заданное время.Future.wait(list)— ждёт все Future параллельно, возвращает список результатов.Future.any(list)— завершается, как только завершится первый Future..then(fn),.catchError(fn),.whenComplete(fn)— callback-стиль (альтернатива async/await)..timeout(duration)— бросаетTimeoutExceptionесли Future не завершился вовремя.
Event loop и порядок выполнения
void main() {
print('1: sync'); // сразу
Future.value('microtask').then((_) => print('2: microtask')); // microtask queue
Future(() => print('3: event queue')); // event queue
print('4: sync'); // сразу
}
// Вывод: 1: sync, 4: sync, 2: microtask, 3: event queue
Подводные камни
- Забытый await: вызов
asyncFn()без await не ждёт завершения; функция запускается, но ошибки и результат теряются — используйтеunawaited(asyncFn())изdart:asyncдля явного намерения. - Блокировка event loop: тяжёлые синхронные вычисления внутри async-функции блокируют весь event loop Flutter; выносите их в
compute()илиIsolate.run(). - async в initState: Flutter запрещает await в
initState; используйте паттернFuture.microtask(() async { ... })илиWidgetsBinding.instance.addPostFrameCallback. - BuildContext после await: контекст может стать невалидным после await; проверяйте
mountedу StatefulWidget или используйте ref.read в Riverpod. - Необработанные ошибки в Future.wait: при ошибке одного Future весь Future.wait бросает исключение; остальные Future продолжают выполняться — для изоляции используйте
eagerError: falseили индивидуальные try-catch. - then() vs await: вложенные .then() быстро превращаются в callback hell; предпочитайте async/await для линейного кода.
Common mistakes
- Сводить «Dart Futures и как использовать
async/await» к синтаксису и не объяснять event loop. - Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии dart-6.
- Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.
What the interviewer is testing
- Формулирует точную модель для «Dart Futures и как использовать
async/await» и подтверждает ее корректным примером. - Умеет связать ответ с Future и Stream, тестированием и отладкой на устройстве.
- Называет ограничения подхода dart-6, включая производительность, память и сопровождение.