2024 Update: Dart 3 Solution (Records/Patterns)
With Dart 3, you no longer need a helper. You can use records (up to 9 futures).
// Calling this will start the function execution
Future<List<Foo>> foos = downloader.getFoos();
Future<List<Bar>> bars = downloader.getBars();
// Will run in parallel until both are done
final (foos, bars) = await (foosFunction, barsFunction).wait;
// Do stuff with the results since both are complete - and type safe!
print(foos[0]);
print(bars[0]);
Pre-Dart 3 Solution
I made a helper function that utilizes some of the logic in the other answers. It uses the tuple
package, but you can write it yourself pretty easily (included below).
// Put this in future_utils.dart
/// Represents a 2-tuple, or pair.
class Tuple2<T1, T2> {
/// Returns the first item of the tuple
final T1 item1;
/// Returns the second item of the tuple
final T2 item2;
/// Creates a new tuple value with the specified items.
const Tuple2(this.item1, this.item2);
}
Future<Tuple2<T1, T2>> await2<T1, T2>(
Future<T1> firstFuture,
Future<T2> secondFuture) async {
late T1 item1;
late T2 item2;
await Future.wait<void>([
(() async => item1 = await firstFuture)(),
(() async => item2 = await secondFuture)(),
]);
return Tuple2(item1, item2);
}
Then call it:
Future<List<Foo>> foos = downloader.getFoos();
Future<List<Bar>> bars = downloader.getBars();
// Will run in parallel
Tuple2<List<Foo>, List<Bar>> results = await await2(foos, bars);
// Do stuff with the results since both are complete
print(results.item1[0]);
print(results.item2[0]);
Now if you want one for 3 arguments, 4, or more you can just copy and paste (await3
, await4
). This isn't too crazy of a pattern, I've used it for multiple lets in Kotlin and also that Tuple library I linked.