Beginner · Async Dart and packages · topic 9 of 50 · 35 min
Futures and async/await
Explanation
One thread, an event loop
A Dart program (and each Flutter app's UI) runs your code on a single thread with an event loop. The event loop is like a to-do list: it takes the next event (a tap, a timer, a network response), runs the code for it, then takes the next. If one piece of code takes too long, everything else waits, and in Flutter the screen freezes. So slow operations like network calls, file reads and timers are asynchronous: they start, and their result arrives later as a new event.
Futures
Future<int> fetchBalance() {
return Future.delayed(const Duration(seconds: 1), () => 2500); // pretend network call
}
void main() {
print('Loading...');
fetchBalance().then((b) => print('Balance: Rs $b'));
print('This line runs before the balance arrives');
}A Future is in one of three states: uncompleted (still waiting), completed with a value, or completed with an error. Network libraries, file APIs, databases and timers all return Futures, so you will meet them everywhere in Flutter, for example when loading data for a screen.
Notice the order of output in the example above: the last print line runs first, because then only registers what to do later. Beginners often expect the balance to print first; understanding this order is the key to async code.
async and await
Chaining then calls gets hard to read. async and await let you write asynchronous code that reads top to bottom. A function marked async returns a Future automatically. Inside it, await pauses that function until a Future completes; the event loop keeps running other events in the meantime.
Future<int> fetchBalance() async {
await Future.delayed(const Duration(seconds: 1));
return 2500;
}
Future<void> main() async {
print('Loading...');
final balance = await fetchBalance();
print('Balance: Rs $balance');
}Error handling
Future<String> fetchProfile() async {
await Future.delayed(const Duration(milliseconds: 300));
throw Exception('No internet');
}
Future<void> main() async {
try {
final p = await fetchProfile();
print(p);
} catch (e) {
print('Could not load: $e');
} finally {
print('Hide spinner'); // always runs
}
}Running Futures together
Future<String> loadUser() => Future.delayed(const Duration(seconds: 1), () => 'Asha');
Future<int> loadOrders() => Future.delayed(const Duration(seconds: 1), () => 7);
Future<void> main() async {
final sw = Stopwatch()..start();
final (user, orders) = await (loadUser(), loadOrders()).wait; // Dart 3 record wait
print('$user has $orders orders in ${sw.elapsedMilliseconds} ms'); // about 1000 ms, not 2000
final all = await Future.wait([loadUser(), loadUser()]); // list version
print(all);
}Common mistakes
- Forgetting await: you get a Future (printed as Instance of 'Future<int>') instead of the value, and the code continues too early. The analyser can warn about unawaited futures.
- Awaiting independent calls one by one, doubling the waiting time. Use Future.wait or record .wait.
- Marking a function async but returning void instead of Future<void>, so callers cannot await it or catch its errors.
- Thinking async runs code on another thread. It does not: it only lets the single thread do other work while waiting.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Futures and async/await · 1/6
Dart runs your code on one thread with an event loop. Long work would freeze the app.
Prefer a video by a teacher? Find free videos on “dart futures async await event loop explained flutter” on YouTube ↗
In real life: Loading a checkout page
A grocery app's checkout needs the cart, the saved addresses and available coupons, each from a separate API taking about 400 ms. Awaiting them one after another takes 1.2 seconds; starting all three and waiting with Future.wait takes about 0.4 seconds. A try/catch shows "Check your internet" if any call fails, and finally hides the loading spinner either way.
Future<void> loadCheckout() async {
try {
final results = await Future.wait([
Future.delayed(const Duration(milliseconds: 400), () => '3 items'),
Future.delayed(const Duration(milliseconds: 400), () => '2 addresses'),
Future.delayed(const Duration(milliseconds: 400), () => '1 coupon'),
]);
print(results.join(', '));
} catch (e) {
print('Check your internet connection');
} finally {
print('Spinner hidden');
}
}
Future<void> main() => loadCheckout();Practice (0/3 done)
In what order are the lines printed? Future<void> main() async { print('A'); Future.delayed(Duration.zero, () => print('B')); print('C'); }
Two independent calls each take 1 second. With Future.wait, about how long does it take to get both?
In DartPad, write Future<int> fetchPrice(String item) that waits 500 ms and returns a price (throw an Exception for an unknown item). Fetch three prices one by one and time it with Stopwatch, then with Future.wait and time it again. Wrap a call for an unknown item in try/catch.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- StreamsAsync Dart and packages · same module
- Isolates for heavy workAsync Dart and packages · same module
- Packages and pubAsync Dart and packages · same module
- async and awaitJavaScript Programming (language in depth) · Asynchronous JavaScript
- async/await and error handlingFrontend Web Development · Async JavaScript, modules and tools
- Async Rust with tokioRust Programming · Concurrency and async
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is a Future?
Answer: A value that will be available later
It completes with a value or an error.
What does an async function return?
Answer: A Future
async functions return Futures.
Does await block the whole Dart program?
Answer: No, it pauses only the current function while the event loop keeps working
Other events continue.
Where does an error from an awaited Future appear?
Answer: At the await, where try/catch can handle it
It is rethrown at the await.
Two independent requests each take 1 s. With await one after the other, the total is about…Related
Three independent requests each take about 1 second. How long does await Promise.all([a(), b(), c()]) take?Related
Answer: About 1 second
Promise.all starts them together, so the total is about the slowest one. Awaiting them one by one would take about 3 seconds.
What is the danger of a long CPU loop inside an async task?Related
Answer: It blocks the worker thread, so other tasks stall
Tasks must yield at .await points; use spawn_blocking for heavy work.
What kind of work benefits most from async/await?Related
Answer: Waiting for network, disk or database (I/O)
async frees threads during I/O waits.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Async Dart and packages” before its exam: Streams, Isolates for heavy work, Packages and pub.
- Module 3 exam: Async Dart and packages · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Flutter setup and your first app. 50 topics left in the course before the final exam.
← Previous: Dart 3: enums, records, patterns and sealed classes