Dartlang wait more than one future
Asked Answered
S

4

116

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?

Sitwell answered 11/2, 2017 at 12:54 Comment(0)
L
222

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

Liebowitz answered 11/2, 2017 at 12:56 Comment(6)
You can use map as well: await Future.wait(data.map((d)=>d.loadData())).Niggerhead
Would like to point out that to fix the above code, do the following: List<Future> futures = []; instead of varSeamanlike
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 exampleNormi
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.Beaker
@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!!!Noisy
This doesn't work with FutureOr thoughShadbush
T
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;
  });
}
Thetes answered 10/11, 2020 at 11:34 Comment(0)
S
19

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 (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 Tuple2(result1, result2);
}
Stricklin answered 28/5, 2021 at 10:12 Comment(3)
This worked beautifully! Thank you @tobias-marschall... Here's my example using your helper method!!! gist.github.com/marcellodesales/…Whalen
What is the purpose of returning Future.value of the result tuple? Is it not redundant given that the result of an async function is already a Future?Aback
@Aback there is no reason other than that it was a mistake. I removed it.Stricklin
S
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))
Shadbush answered 21/7, 2022 at 16:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.