100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Futures and async/await

Learn how Dart represents asynchronous computations with Future objects and how async/await syntax lets you write non-blocking code that reads like synchronous code.

Async & GenericsBeginner8 min readJul 10, 2026
Analogies

Understanding the Future Type

In Dart, a Future<T> represents a value of type T (or an error) that will be available at some point after an asynchronous operation completes. A Future starts in an uncompleted state and moves to a completed state either with a value (via Future.value or a resolved async call) or with an error (via Future.error). Common sources of Futures include Future.delayed for simulating a wait, http.get() calls from the http package, or File.readAsString() for disk I/O. Unlike a plain value, you cannot read a Future's result synchronously — you must either register a callback with .then() or use await inside an async function.

🏏

Cricket analogy: A Future is like a DRS review sent upstairs after a close LBW shout — the umpire's on-field call stays 'pending', and only when the third umpire replies does play resume with the confirmed verdict, exactly as a Future resolves to a value or an error.

async and await Keywords

Marking a function with the async keyword changes its return type to a Future (or Future<void> if there's no explicit return) and enables the use of await inside its body. The await keyword pauses execution of the async function — without blocking the isolate's event loop — until the awaited Future completes, then unwraps its value or throws if the Future completed with an error. This lets you write asynchronous code in a linear, top-to-bottom style instead of nesting callbacks: for example, var data = await fetchUser(); print(data.name); reads just like synchronous code even though fetchUser() might take 500ms to hit a REST API.

🏏

Cricket analogy: await is like a non-striker backing up at the crease during a run-out review — the game doesn't restart until the third umpire's verdict returns, but the stadium clock and other matches on TV keep running.

dart
Future<String> fetchUserName(int id) async {
  final response = await http.get(Uri.parse('https://api.example.com/users/$id'));
  if (response.statusCode != 200) {
    throw Exception('Failed to load user $id');
  }
  return jsonDecode(response.body)['name'] as String;
}

Future<void> main() async {
  try {
    final name = await fetchUserName(42);
    print('User name: $name');
  } catch (e) {
    print('Error fetching user: $e');
  } finally {
    print('Request finished.');
  }
}

Chaining Futures with then(), catchError(), and whenComplete()

Before async/await, Futures were composed with .then() for success callbacks, .catchError() for handling failures, and .whenComplete() for cleanup that runs regardless of outcome — similar to try/finally. These methods still matter in Dart: they're useful for fire-and-forget chains or library code that shouldn't assume it's running inside an async context. To run multiple independent Futures concurrently rather than sequentially, Future.wait([future1, future2, future3]) returns a single Future that completes once every Future in the list completes, collecting their results into a List.

🏏

Cricket analogy: Chaining .then() calls is like a batting order where each batter's innings kicks off the next — opener finishes, then number three walks in — while Future.wait resembles a fielding drill where two players train simultaneously and the coach waits for both to finish before starting the next drill.

Future.wait() is especially useful for fan-out patterns: kicking off several independent network requests at once and waiting for all of them before rendering a screen, rather than awaiting each one sequentially and paying the latency cost of every request added together.

Error Handling and the Event Loop

When code inside an async function throws, or when an awaited Future completes with an error, Dart converts that into an exception you can catch with an ordinary try/catch block wrapped around the await expression. Uncaught errors from a Future propagate to the current Zone's error handler or crash the isolate for top-level code, and unlike synchronous exceptions, they aren't delivered 'right now' — they're scheduled on Dart's microtask queue, which drains after the current synchronous code finishes but before the event loop processes the next timer or I/O event. This ordering (synchronous code, then microtasks, then macrotasks like Timer) is why an await inside a loop still yields control back to the event loop between iterations.

🏏

Cricket analogy: It's like a bowler's no-ball only being flagged after the third umpire reviews the front-foot replay — the exception (no-ball call) surfaces on a delayed review queue, not instantly when the ball is bowled, similar to how the microtask queue delivers errors after the current synchronous over finishes.

A Future that's created but never awaited or given a .catchError() handler can fail silently — its error may only surface as an 'Unhandled exception' log line with no clear connection to where it was triggered. Always await fire-and-forget calls deliberately, or explicitly attach error handling.

  • A Future<T> represents a value or error that becomes available asynchronously; it starts uncompleted and later completes exactly once.
  • async functions always return a Future; await pauses only that function's execution without blocking the event loop.
  • await unwraps a Future's value or rethrows its error as a normal Dart exception you can catch with try/catch.
  • Use .then()/.catchError()/.whenComplete() when you need callback-style composition instead of async/await.
  • Future.wait() runs multiple Futures concurrently and completes once all of them finish.
  • Errors from Futures are delivered via the microtask queue, after current synchronous code but before timers.
  • Forgetting to await a Future can silently swallow errors — always await or explicitly handle fire-and-forget calls.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#DartStudyNotes#FuturesAndAsyncAwait#Futures#Async#Await#Future#Concurrency#StudyNotes#SkillVeris