Lesson 14 · 14 of 20
Future.wait and async errors · Dart
Run several requests in parallel with Future.wait in Dart and handle their errors with try/catch, timeout and onError, with output that never changes.

Awaited one after another, three calls of 60, 10 and 30 ms would take 100 ms. `Future.wait` starts them all at once and waits for them to finish, so it takes as long as the slowest. The key to a predictable result is that the list of results follows the order of the input list, not the order in which they finish: that is why Stocks always prints [35, 63, 21].
fetchStock throws a StateError for codes starting with X. Inside an async function, an exception makes its Future complete with an error, and await rethrows that error in whoever is waiting. So an ordinary try/catch with on StateError around await Future.wait(...) is all it takes.
To wait for futures of different types at the same time, Dart 3 lets you group them in a record and call .wait: (Future.value('Mug'), fetchStock(...)).wait returns a (String, int) record that is destructured into name and stock, each with its own type.
`timeout` turns a call that is too slow into a TimeoutException, which comes from dart:async: SLOW-API takes 300 ms and is abandoned after 50. And when a failure is not serious, `onError` replaces the error with a fallback value: the unknown product gives 0 instead of an exception.
Code · main.dart
import 'dart:async';Future<int> fetchStock(String sku, int ms) async { await Future.delayed(Duration(milliseconds: ms)); // simulated network if (sku.startsWith('X')) throw StateError('unknown product $sku'); return sku.length * 7;}Future<void> main() async { // In parallel: results come back in list order, not in finishing order. final stocks = await Future.wait( [fetchStock('MUG-1', 60), fetchStock('TSHIRT-22', 10), fetchStock('CAP', 30)]); print('Stocks: $stocks'); // If one fails, await throws and an ordinary try/catch handles it. try { await Future.wait([fetchStock('MUG-1', 10), fetchStock('X-404', 5)]); } on StateError catch (e) { print('Failed: ${e.message}'); } // A record of futures of different types, awaited together. final (name, stock) = await (Future.value('Mug'), fetchStock('MUG-1', 20)).wait; print('$name: $stock in stock'); // A timeout turns a call that is too slow into an error. try { await fetchStock('SLOW-API', 300).timeout(const Duration(milliseconds: 50)); } on TimeoutException { print('Gave up after 50 ms'); } // Or recover with a fallback value instead of an exception. print('Fallback: ${await fetchStock('X-1', 5).onError((e, _) => 0)}');}Output · dart run main.dart
Stocks: [35, 63, 21] Failed: unknown product X-404 Mug: 35 in stock Gave up after 50 ms Fallback: 0
Key points
Future.waitruns in parallel and returns the results in order.- An error in a
Futureresurfaces at theawait: catch it withtry/catch. (f1, f2).waitwaits for futures of different types.timeoutputs a time limit on a call.onErrorreturns a fallback value when something fails.
Exercise
Add a third element to the record, fetchStock('CAP', 15), destructure it into a caps variable and print all three values on one line.