Every network call, file read and database query in Dart and Flutter returns a Future.
A `Future<T>` represents a value (or error) that will be available later. Functions that do I/O return futures instead of blocking, because Dart runs your code on a single thread per isolate.
Mark a function async and use await to wait for a future without blocking:
Future<User> loadUser(int id) async {
final json = await api.get('/users/$id');
return User.fromJson(json);
}An async function always returns a Future, even if the body returns a plain value. Use Future<void> when nothing is returned. Errors from awaited futures are thrown at the await, so ordinary try/catch/finally works.
Important behaviors:
- An
asyncfunction runs synchronously until its firstawait, then returns the future to its caller. - Sequential
awaits run one after another. For independent work, start the futures first and wait together:await Future.wait([a(), b()]), or with recordsfinal (u, p) = await (loadUser(), loadPosts()).wait;. .timeout(Duration(...))fails a slow future with aTimeoutException.- A future you forget to await runs anyway, but its errors become uncaught. Enable the
unawaited_futureslint and wrap intentional fire-and-forget calls inunawaited(...).
Future.delayed, Future.value and Completer create futures yourself; the latter bridges callback-based APIs.
Example
import 'dart:async';
Future<String> fetch(String what, int ms) async {
await Future.delayed(Duration(milliseconds: ms));
if (what.isEmpty) throw ArgumentError('empty request');
return '$what loaded';
}
Future<void> main() async {
final sw = Stopwatch()..start();
final a = await fetch('user', 200);
final b = await fetch('posts', 200);
print('$a, $b in ~${sw.elapsedMilliseconds ~/ 100 * 100} ms'); // ~400 ms
sw.reset();
final (u, p) = await (fetch('user', 200), fetch('posts', 200)).wait;
print('$u, $p in ~${sw.elapsedMilliseconds ~/ 100 * 100} ms'); // ~200 ms
try {
await fetch('', 10);
} on ArgumentError catch (e) {
print('failed: ${e.message}'); // failed: empty request
}
try {
await fetch('slow', 500).timeout(const Duration(milliseconds: 50));
} on TimeoutException {
print('timed out'); // timed out
}
}Remember
asyncfunctions return a Future;awaitunwraps it- Start independent futures together and wait with
Future.waitor(a, b).wait - Errors surface at
awaitand are caught with try/catch
Watch out for
- Forgetting
await, so errors go uncaught and code runs out of order.