110

I want to do something after a lot of future functions are done, but I do not know how to write the code in dart? the code is like this:

for (var d in data) {
  d.loadData().then()
}
// when all loaded
// do something here

but I don't want to wait for them one by one:

for (var d in data) {
  await d.loadData(); // NOT NEED THIS
}

how to write those code in dart?

Shihab Uddin
  • 6,699
  • 2
  • 59
  • 74
bitnick
  • 1,903
  • 3
  • 16
  • 22

4 Answers4

209

You can use Future.wait to wait for a list of futures:

import 'dart:async';

Future main() async {
  var data = [];
  var futures = <Future>[];
  for (var d in data) {
    futures.add(d.loadData());
  }
  await Future.wait(futures);
}

DartPad example

Bruno Finger
  • 2,105
  • 3
  • 27
  • 47
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 42
    You can use `map` as well: `await Future.wait(data.map((d)=>d.loadData()))`. – lrn Feb 13 '17 at 06:50
  • 9
    Would like to point out that to fix the above code, do the following: ```List futures = [];``` instead of `var` – Saad Ardati Apr 27 '19 at 18:18
  • 6
    Since it is not 100% clear from the question or answer or docs: the processes all start at the same time and run in parallel see [dartpad example](https://dartpad.dartlang.org/20ae2ced5f4d5dfc760339b4de6584f5) – Jannie Theunissen Feb 28 '20 at 08:08
  • 12
    That's not entirely true. They are started one after the other, because in Dart within one isolate only a single code execution can run, but when one of the running yields, because it waits for some async call to complete, then the next is started (or continued) before the previous completes. So they run concurrently (not parallel) according to Darts event-queue driven method. – Günter Zöchbauer Feb 28 '20 at 08:20
  • 1
    @JannieTheunissen I'd like to appreciate the clarity in your example. Years ago when I was wrestling with this in JS.. I learnt it this very same way. Thanks & great work!!! – Yo Apps Mar 13 '20 at 09:26
  • This doesn't work with FutureOr though – Praytic Jul 21 '22 at 16:43
23

Existing answer gives enough information, but I want to add a note/warning. As stated in the docs:

The value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures.

So, that means that the example below will return 4 as the first element (index 0), and 2 as the second element (index 1).

import 'dart:async';

Future main() async {
  print('start');

  List<int> li = await Future.wait<int>([
    fetchLong(),  // longer (which gives 4) is first
    fetchShort(), // shorter (which gives 2) is second
  ]);

  print('results: ${li[0]} ${li[1]}'); // results: 4 2
}

Future<int> fetchShort() {
  return Future.delayed(Duration(seconds: 3), () {
    print('Short!');
    return 2;
  });
}

Future<int> fetchLong() {
  return Future.delayed(Duration(seconds: 5), () {
    print('Long!');
    return 4;
  });
}
Aleksandar
  • 3,558
  • 1
  • 39
  • 42
15

If you want to wait for multiple futures of different types and also support null-safety then you can add a helper function similar to the following when using Dart >= 3.0:

Future<(T1, T2)> waitConcurrently<T1, T2>(
  Future<T1> future1,
  Future<T2> future2,
) async {
  late T1 result1;
  late T2 result2;

  await Future.wait([
    future1.then((value) => result1 = value),
    future2.then((value) => result2 = value)
  ]);

  return Future.value((result1, result2));
}

Dart < 3.0 does not support tuples natively, but there is a package from Google which does: https://pub.dev/packages/tuple

import 'package:tuple/tuple.dart';

Future<Tuple2<T1, T2>> waitConcurrently<T1, T2>(
  Future<T1> future1,
  Future<T2> future2,
) async {
  late T1 result1;
  late T2 result2;

  await Future.wait([
    future1.then((value) => result1 = value),
    future2.then((value) => result2 = value)
  ]);

  return Future.value(Tuple2(result1, result2));
}
Tobias Marschall
  • 2,355
  • 3
  • 22
  • 40
  • This worked beautifully! Thank you @tobias-marschall... Here's my example using your helper method!!! https://gist.github.com/marcellodesales/39857e464b38167f0631150ee6238943 – Marcello DeSales Jul 17 '21 at 06:48
3

In addition, I'd like to supplement Günter Zöchbauer's answer with FutureOr variant. You'll need to convert your FutureOr<T> variable to Future<T> first and then call wait:

Future.wait(list.map((x) async => x))
Praytic
  • 1,771
  • 4
  • 21
  • 41