Futures, async, and await
Waiting without freezing
Some things take time: downloading a file, reading a database, waiting for a timer. Dart handles this with a Future — a value that does not exist yet, but will later.
Think of a Future like a ticket at a restaurant. You order now; the meal arrives later. The ticket (Future) is the promise of the meal.
Future<String> fetchMessage() async {
await Future.delayed(Duration(seconds: 1));
return 'done';
}This function is marked async, which means it may pause and resume instead of blocking everything else.
await: pausing inside an async function
The keyword await means "pause here until the Future is finished, then continue." Only an async function can use await.
Future<void> main() async {
print('start');
final message = await fetchMessage();
print(message); // prints after about one second
}Note that main is async too, because it awaits. A program's work happens on a single thread, but while awaiting, Dart is free to do other pending work — the program does not freeze.
Handling errors in async code
If the Future fails, it carries an error instead of a value. The familiar try-catch from synchronous code works with await:
Future<void> main() async {
try {
final message = await fetchMessage();
print(message);
} catch (e) {
print('failed: $e');
}
}Because await is a normal expression, you can wrap it in the same try-catch you use everywhere else. Async errors become ordinary exceptions.
Running work in parallel
Sometimes you don't want to wait for tasks one at a time. Use Future.wait to start several and await them all together:
Future<String> task(String name, int ms) async {
await Future.delayed(Duration(ms: ms));
return '$name finished';
}
Future<void> main() async {
final results = await Future.wait([task('a', 300), task('b', 200)]);
print(results); // [a finished, b finished]
}The total wait is about 300 milliseconds, not 500, because the tasks run at the same time.
Common mistakes
A few traps show up often:
- Forgetting async: using
awaitinside a function not markedasyncis a compile error. - Awaiting in a loop by accident:
for (final url in urls) { await fetch(url); }waits for each one in turn. For parallel work, collect Futures in a list and useFuture.wait. - Calling an async function without awaiting it: the work still starts, but you get a Future, not the result — and errors may go unnoticed.
- Using
asyncon main withoutFuture<void>: preferFuture<void> main() asyncso the tooling knows the program ends when the async work does.
Show diagram source
sequenceDiagram
participant M as main
participant F as fetchMessage
M->>F: call fetchMessage()
F-->>M: returns Future immediately
Note over F: waits 1 second
M->>M: await (pause this function only)
F-->>M: Future completes with 'done'
M->>M: continue with messageExercise
What is printed first in Future<void> main() async { print('a'); final x = await somethingSlow(); print('b'); }?
Show answer
'a'. The lines before the await run immediately; 'b' only prints after the Future completes.
Exercise
You need to load three files, and each takes one second. How do you do it in about one second instead of three?
Show answer
Start all three loads at once (collect the Futures in a list) and await them together with Future.wait([loadA(), loadB(), loadC()]).
Exercise
What happens if an awaited Future fails and you did not use try-catch?
Show answer
The async function stops with that error, and the returned Future completes with the error, which surfaces as an unhandled exception.
Spotted a mistake, or code that does not work?