Dart Future.等待多个future并返回不同类型的结果

问题描述 投票:0回答:6

我使用 Flutter 从服务器下载 3 组不同的数据,然后对所有 3 组数据执行某些操作。我可以这样做:

List<Foo> foos = await downloader.getFoos();
List<Bar> bars = await downloader.getBars();
List<FooBars> foobars = await downloader.getFooBars();

processData(foos, bars, foobars);

但我更喜欢并行异步下载所有 3 个数据集。我看到 Dart 有这个 Future.wait 方法:

Future<List<T>> wait <T>(
   Iterable<Future<T>> futures, {
   bool eagerError: false, 
   void cleanUp(
      T successValue
   )
}) 

但是看起来这只会返回相同类型(T)的值。我有 3 种不同的类型,所以我不知道如何使用它并取回我的 3 个数据集。

实现这一目标的最佳替代方法是什么?

谢谢!

flutter asynchronous dart concurrency future
6个回答
49
投票

您需要将每个

Future<T>
调整为常见类型的
Future
。您可以使用
Future<void>
并分配结果,而不是依赖返回值:

late List<Foo> foos;
late List<Bar> bars;
late List<FooBars> foobars;

await Future.wait<void>([
  downloader.getFoos().then((result) => foos = result),
  downloader.getBars().then((result) => bars = result),
  downloader.getFooBars().then((result) => foobars = result),
]);

processData(foos, bars, foobars);

或者,如果您更喜欢

await
而不是
.then()
,则
Future.wait
调用可能是:

await Future.wait<void>([
  (() async => foos = await downloader.getFoos())(),
  (() async => bars = await downloader.getBars())(),
  (() async => foobars = await downloader.getFooBars())(),
]);

4
投票

我制作了一个辅助函数,它利用了其他答案中的一些逻辑。它使用

tuple
包,但你可以很容易地自己编写它(包括在下面)。

// 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> Function() firstFuture,
    Future<T2> Function() secondFuture) async {
  late T1 item1;
  late T2 item2;
  await Future.wait<void>([
    (() async => item1 = await firstFuture())(),
    (() async => item2 = await secondFuture())(),
  ]);
  return Tuple2(item1, item2);
}

然后调用它:

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]);

现在,如果您想要一个用于 3 个、4 个或更多参数的参数,您只需复制并粘贴即可(

await3
await4
)。这并不是一种“太疯狂”的模式,我已经将它用于 Kotlin 中的多个let以及我链接的元组库。 我认为不可能以超级好的方式做到这一点。你所能做的就是这样:


2
投票

我想说正确的答案是使用官方的 
async

2
投票
FutureGroup

: void main() { Future<String> future1 = getData(2); Future<String> future2 = getData(4); Future<String> future3 = getData(6); FutureGroup futureGroup = FutureGroup(); futureGroup.add(future1); futureGroup.add(future2); futureGroup.add(future3); futureGroup.close(); futureGroup.future.then((value) => {print(value)}); } Future<String> getData(int duration) async { await Future.delayed(Duration(seconds: duration)); //Mock delay return "This a test data"; }

    

嗯,类型 T 是泛型类型

0
投票

如果您使用的是

FutureBuilder

,您可以使用它访问不同的结果。 (与您在

Future.wait

方法中放置它们的顺序相同)


snapshot.data[0] // maybe type List<Foo> snapshot.data[1] // maybe type List<Bar> snapshot.data[2] // maybe type String
    

Future<List<Foo>> foosFuture = downloader.getFoos();
Future<List<Bar>> barsFuture = downloader.getBars();
Future<List<FooBars>> foobarsFuture = downloader.getFooBars();

final (foos, bars, foobars) = await (foosFuture, barsFuture, foobarsFuture).wait;

processData(foos, bars, foobars);

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.