Future.wait în Dart

Future.wait așteaptă mai multe future-uri în paralel și dă lista rezultatelor; Future.any dă primul rezultat terminat.

Sintaxă
static Future<List<T>> wait<T>(Iterable<Future<T>> futures, {bool eagerError = false, void cleanUp(T value)?})
static Future<T> any<T>(Iterable<Future<T>> futures)

Ce face Future.wait

Future.wait(lista) pornește așteptarea tuturor deodată și se termină când s-au terminat toate. Rezultatul este o listă cu valorile, în aceeași ordine ca future-urile, nu în ordinea terminării. Durata totală este cât cea mai lentă operație, nu suma lor.

Dacă unul eșuează, wait se termină cu acea eroare. Cu eagerError: true, eroarea vine imediat, fără să mai aștepte restul. Pentru future-uri de tipuri diferite, Dart 3 are și forma cu records: final (a, b) = await (f1, f2).wait;.

Future.any(lista) se termină cu rezultatul (sau eroarea) primului future care se termină. Restul continuă, dar rezultatele lor sunt ignorate.

Parametri

Parametru Descriere
futures Future-urile așteptate.
eagerError Pentru wait: dacă e true, prima eroare oprește imediat așteptarea.
cleanUp Pentru wait: funcție chemată cu valorile reușite dacă vreun future a eșuat.

Ce returnează

wait: un Future<List<T>>. any: un Future<T> cu primul rezultat.

Exemple

Exemplul 1: Trei cereri în paralel

Cererile durează 120, 60 și 90 ms. Cu wait, totul durează cât cea mai lentă, iar ordinea rezultatelor este cea din listă.

Future<int> temperatura(String oras, int ms) =>
    Future.delayed(Duration(milliseconds: ms), () => oras.length * 5);

Future<void> main() async {
  final ceas = Stopwatch()..start();
  final rezultate = await Future.wait([
    temperatura('Iași', 120),
    temperatura('Cluj', 60),
    temperatura('Constanța', 90),
  ]);
  print(rezultate);
  print('Sub 300 ms în total: ${ceas.elapsedMilliseconds < 300}');

  final (nume, varsta) = await (Future.value('Ana'), Future.value(21)).wait;
  print('$nume are $varsta ani');
}

Rezultat

[20, 20, 45]
Sub 300 ms în total: true
Ana are 21 ani

Exemplul 2: Primul server care răspunde, cu Future.any

Future<String> server(String nume, int ms) =>
    Future.delayed(Duration(milliseconds: ms), () => nume);

Future<void> main() async {
  final primul = await Future.any([
    server('server-București', 80),
    server('server-Frankfurt', 30),
    server('server-Amsterdam', 60),
  ]);
  print('A răspuns primul: $primul');
}

Rezultat

A răspuns primul: server-Frankfurt

Exemplul 3: O eroare în Future.wait

Future<int> stoc(String produs) async {
  await Future.delayed(const Duration(milliseconds: 10));
  if (produs == 'kiwi') throw StateError('$produs nu există');
  return produs.length;
}

Future<void> main() async {
  try {
    await Future.wait([stoc('mere'), stoc('kiwi'), stoc('pere')]);
  } on StateError catch (e) {
    print('Eroare: ${e.message}');
  }
}

Rezultat

Eroare: kiwi nu există

Greșeli frecvente

  • Aștepți pe rând, cu await într-o buclă, operații care nu depind una de alta. Durata se adună; cu Future.wait rulează în paralel.
  • Crezi că lista rezultatelor este în ordinea terminării. Este în ordinea future-urilor din listă.

Comenzi înrudite

  • Future: O valoare care va fi gata mai târziu (citirea unui fișier, un răspuns de la server); o aștepți cu await.
  • Future.forEach: forEach rulează o acțiune asincronă pe rând pentru fiecare element; doWhile repetă o acțiune cât timp returnează true.
  • Future.timeout: Limitează cât aștepți un future: după timpul dat, aruncă TimeoutException sau folosește onTimeout.
  • records: Grupuri de valori anonime și imutabile, de forma (a, b) sau (nume: a), ideale pentru a întoarce mai multe valori.