gpt4 book ai didi

Dart Future.wait for multiple futures and get back results of different types(DART期货.等待多个期货,并返回不同类型的结果)

转载 作者:bug小助手 更新时间:2023-10-27 20:34:35 28 4
gpt4 key购买 nike



I'm using Flutter to download 3 different sets of data from a server, then do something with all 3 sets. I could do this:

我正在使用Ffltter从服务器下载3个不同的数据集,然后对所有3个集做一些操作。我可以这样做:



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

processData(foos, bars, foobars);


But I'd prefer to download all 3 data sets asynchronously in parallel. I've seen that Dart has this Future.wait method:

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



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


However it looks like this will only return values of the same type (T). I have 3 different types, so I don't see how I can use this and get my 3 data sets back.

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



What's the best alternative way to achieve this?

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



Thanks!

谢谢!


更多回答

I've added an updated solution that will retain type safety with multiple parallel futures in both pre-dart 3 and post-dart 3: stackoverflow.com/a/71178612/1759443

我添加了一个更新的解决方案,它将在DART 3之前和DART 3之后使用多个并行期货来保持类型安全:stackoverflow.com/a/71178612/1759443

优秀答案推荐

In Dart 3, you should use a Record of Futures instead of a List/Iterable so that you can have heterogeneous types. Dart 3 provides wait extensions for such Records that are similar to Future.wait. (See sudormrfbin's answer for an example.)

在DART 3中,您应该使用期货记录而不是List/Iterable,这样您就可以拥有异类类型。DART 3为类似于Future.Wait的这类记录提供等待扩展。(有关示例,请参阅susormrfbin的答案。)


If you must use Future.wait, you need to adapt each of your Future<T>s to a common type of Future. You could use Future<void> and assign the results instead of relying on return values:

如果您必须使用Future.Wait,则需要将您的每个Future S修改为一种常见的Future类型。您可以使用Future 并分配结果,而不是依赖返回值:


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

Or if you prefer await to .then(), the Future.wait call could be:

或者,如果您更喜欢等待.Then(),则Future.Wait调用可以是:


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


2023 Update: Dart 3 Solution


With Dart 3, you no longer need a helper. You can use records (up to 9 futures).

有了DART 3,你不再需要帮手了。您可以使用记录(最多9个未来)。


// 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.

现在,如果您想要一个用于3个参数、4个或更多参数,您只需复制并粘贴(wait3,wait4)。这并不是一个太疯狂的模式,我已经在Kotlin和我链接的Tuple库中使用了它。



I think is not possible to do in a super nice fashion. All you can do is something like this:

我认为不可能以一种超级好的方式来做。你所能做的就是这样:



void main() async {
List<List<dynamic>> result = await Future.wait<List<dynamic>>([
getStringData(),
getIntData(),
]);

print(result[0]);
print(result[1]);
}

Future<List<String>> getStringData() {
return Future.value(["a", "b"]);
}

Future<List<int>> getIntData() {
return Future.value([1, 2]);
}


I'd say the correct answer is to use the official async package and FutureGroup:

我认为正确的答案是使用官方的Async包和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";
}



If you're using Dart 3, you can take advantage of records to do this:

如果您使用的是DART 3,则可以利用记录来执行以下操作:


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

This works because of the wait property defined on 2-element records via the FutureRecord2 extension. They are defined till FutureRecord9, so you're safe as long as you have less than 10 futures to await on like this.

这是因为通过FutureRecord2扩展在2元素记录上定义了等待属性。它们是在FutureRecord9之前定义的,所以只要你有不到10个期货可以像这样等待,你就是安全的。


There's a section in the language tour that covers this better than the API docs.

语言教程中有一节比API文档更好地介绍了这一点。



Well, type T is a generic type

类型T是一个泛型类型



You know your types, so you can work with them.

你知道你的类型,所以你可以和他们一起工作。



If your are using a FutureBuilder, you can access the different results using this. (same order you put them in the Future.wait method)

如果您使用的是FutureBuilder,则可以使用此选项访问不同的结果。(与在Future.Wait方法中放置它们的顺序相同)



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

更多回答

How does this solve the problem? FutureGroup would have the same problems with heterogeneous Futures as Future.wait.

这如何解决问题呢?FutureGroup在异质期货方面将面临与Future.Wait相同的问题。

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com