DMarlon Studio

Lección 14 · 14 de 20

Future.wait y errores asíncronos · Dart

Lance varias peticiones en paralelo con Future.wait en Dart y trate sus errores con try/catch, timeout y onError, con una salida siempre igual.

Dart · Future.wait y errores asíncronos en DMarlon Studio: el código del ejemplo y su salida en la terminal

Con await una tras otra, tres llamadas de 60, 10 y 30 ms tardarían 100 ms. `Future.wait` las lanza todas a la vez y espera a que acaben, así que tarda lo que la más lenta. Lo importante para un resultado predecible es que la lista de resultados sigue el orden de la lista de entrada, no el orden en que terminan: por eso Stocks sale siempre [35, 63, 21].

fetchStock lanza StateError con los códigos que empiezan por X. Dentro de una función async, una excepción hace que su Future termine con error, y al hacer await ese error se lanza de nuevo en quien espera. Por eso basta un try/catch normal, con on StateError, alrededor de await Future.wait(...).

Para esperar a la vez futures de tipos distintos, Dart 3 permite agruparlas en un record y usar .wait: (Future.value('Mug'), fetchStock(...)).wait devuelve un record (String, int) que se desestructura en name y stock, cada uno con su tipo.

`timeout` convierte una llamada demasiado lenta en una TimeoutException, que viene de dart:async: SLOW-API tarda 300 ms y se abandona a los 50. Y cuando un fallo no es grave, `onError` sustituye el error por un valor de reserva: el producto desconocido da 0 en vez de una excepción.

Código · 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)}');}

Salida · dart run main.dart

Stocks: [35, 63, 21]
Failed: unknown product X-404
Mug: 35 in stock
Gave up after 50 ms
Fallback: 0

Para recordar

  • Future.wait ejecuta en paralelo y devuelve los resultados en orden.
  • Un error en una Future reaparece en el await: captúrelo con try/catch.
  • (f1, f2).wait espera futures de tipos distintos.
  • timeout pone un límite de tiempo a una llamada.
  • onError devuelve un valor de reserva si algo falla.

Ejercicio

Añada un tercer elemento al record, fetchStock('CAP', 15), desestructúrelo en una variable caps y escriba los tres valores en una línea.