What is a Future?
A Future<T> represents a value that will be available at some point in the future — the result of an asynchronous computation. It is similar to a Promise in JavaScript. Futures exist in one of three states:
- Uncompleted — still computing
- Completed with a value — success
- Completed with an error — failure
Creating Futures
import 'dart:async';
// Future.value — immediately completed
Future<int> getValue() => Future.value(42);
// Future.error — immediately failed
Future<int> getError() => Future.error(Exception('Oops'));
// Future.delayed — completes after a delay
Future<String> fetchData() => Future.delayed(
Duration(seconds: 2),
() => 'Data loaded',
);
// Using a Completer for manual control
Future<String> manualFuture() {
final completer = Completer<String>();
Future.delayed(Duration(seconds: 1), () {
completer.complete('Done!');
// or completer.completeError(Exception('Failed'));
});
return completer.future;
}
then / catchError / whenComplete
fetchData()
.then((data) => print('Got: $data'))
.catchError((e) => print('Error: $e'))
.whenComplete(() => print('Finished'));
// Chaining transforms with then:
Future.value(' hello world ')
.then((s) => s.trim())
.then((s) => s.split(' '))
.then((words) => words.map((w) =>
w[0].toUpperCase() + w.substring(1)).join(' '))
.then(print); // Hello World
Chaining Futures
Future<int> step1() => Future.delayed(Duration(milliseconds: 100), () => 10);
Future<int> step2(int v) => Future.delayed(Duration(milliseconds: 100), () => v * 2);
Future<String> step3(int v) => Future.value('Result: $v');
void main() {
step1()
.then(step2)
.then(step3)
.then(print)
.catchError((e) => print('Error: $e'));
// Result: 20
}
Wait for Multiple Futures
Future<void> main() async {
// Run in parallel, wait for all:
var results = await Future.wait([
Future.delayed(Duration(seconds: 1), () => 'First'),
Future.delayed(Duration(seconds: 2), () => 'Second'),
Future.delayed(Duration(milliseconds: 500), () => 'Third'),
]);
print(results); // [First, Second, Third] — takes ~2s total, not 3.5s
// First to complete:
var first = await Future.any([
Future.delayed(Duration(seconds: 3), () => 'Slow'),
Future.delayed(Duration(milliseconds: 100), () => 'Fast'),
]);
print(first); // Fast
}
Note: Future.wait runs futures in parallel and collects all results. Future.any returns the first to complete. If any future in Future.wait fails, the entire wait fails.
🧠 Quiz
1. What does Future.wait do?
- A) Waits for the slowest future and discards others
- B) Runs all futures in parallel and collects results ✅
- C) Runs futures sequentially
- D) Returns the first completed future
2. Which method always runs after a Future, regardless of success or failure?
- A) then
- B) catchError
- C) whenComplete ✅
- D) onError
Summary
Future<T> represents async results. Chain with .then(), handle errors with .catchError(), and cleanup with .whenComplete(). Use Future.wait to run multiple futures in parallel. Use async/await (next lesson) for cleaner syntax over long chains.