Skip to content

Beginner · Async Dart and packages · topic 9 of 50 · 35 min

Futures and async/await

Explanation

A Future is a value that will be ready later, such as the result of a network call. Mark a function async and use await to pause it until a Future completes, without freezing the app: Dart's event loop keeps handling other work meanwhile. Handle errors with try/catch/finally, and run independent Futures together with Future.wait.

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.

Think of it like this: The event loop is like a single cashier at a busy medical store. When a customer needs a medicine from the godown, the cashier does not stand waiting; she gives a token, serves the next customers, and calls the token number when the medicine arrives. A Future is that token.

Futures

dart
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');
}
Future<int> means "an int, later". then registers code to run when it completes.

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.

dart
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');
}
Prints Loading..., then about a second later Balance: Rs 2500.

Error handling

dart
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
  }
}
An error in an awaited Future is thrown at the await, so a normal try/catch works.

Running Futures together

dart
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);
}
Start independent Futures first, then wait for all of them.

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

One thread + event loop

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.

dart
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();
All three run at the same time.

Practice (0/3 done)

Task 1 · Question

In what order are the lines printed? Future<void> main() async { print('A'); Future.delayed(Duration.zero, () => print('B')); print('C'); }

Task 2 · Question

Two independent calls each take 1 second. With Future.wait, about how long does it take to get both?

Task 3 · Practice

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

Question 1

1.What is a Future?

Question 2

2.What does an async function return?

Question 3

3.Does await block the whole Dart program?

Question 4

4.Where does an error from an awaited Future appear?

Read more (free)

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

Answer: 2 s

Sequential awaits add up; Promise.all would take about 1 s.

From async and await

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.

From async/await and error handling

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.

From Async Rust with tokio

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.

From async and await: waiting without blocking

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: Streams →

Next steps

  1. 3 more topics in “Async Dart and packages” before its exam: Streams, Isolates for heavy work, Packages and pub.
  2. Module 3 exam: Async Dart and packages · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. 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