在 Flutter 开发中,经常会遇到多个接口需要同时请求的场景。
例如进入图书详情页时,需要同时获取书籍信息和收藏状态:
ini
final infoFuture = bookApi.getBookInfo(bookId);
final favoriteFuture = favoriteApi.isFavorite(bookId);
两个请求互不依赖,可以使用 Future.wait:
ini
final responses = await Future.wait([
infoFuture,
favoriteFuture,
]);
这种写法可以并发等待多个 Future,但当这些 Future 的返回类型不同时,会出现一个问题:结果列表无法保留每个元素原本的具体类型。
Future.wait 的类型问题
假设两个请求的返回类型分别是:
ini
Future<BookInfo> infoFuture;
Future<bool> favoriteFuture;
我们使用:
ini
final responses = await Future.wait([
infoFuture,
favoriteFuture,
]);
两个 Future 返回的类型不同:
arduino
BookInfo
bool
但 Future.wait 最终返回的是一个 List。
这时无法得到类似:
arduino
List<BookInfo, bool>
这样的类型。
因此,实际使用时通常需要进行类型转换:
ini
final bookInfo = responses[0] as BookInfo;
final isFavorite = responses[1] as bool;
完整代码:
ini
final responses = await Future.wait([
infoFuture,
favoriteFuture,
]);
final bookInfo = responses[0] as BookInfo;
final isFavorite = responses[1] as bool;
代码能运行,但有两个问题。
第一,需要自己记住 responses[0] 和 responses[1] 分别是什么。
第二,需要手动使用 as 转换类型。
当 Future 增多后:
ini
final results = await Future.wait([
bookFuture,
favoriteFuture,
commentsFuture,
authorFuture,
]);
后面就会出现:
ini
final book = results[0] as Book;
final favorite = results[1] as bool;
final comments = results[2] as List<Comment>;
final author = results[3] as Author;
这不仅不直观,也失去了 Dart 静态类型系统带来的便利。
Dart 3 使用 Record 保留类型
如果项目使用 Dart 3,可以使用 Record。
把原来的:
ini
final responses = await Future.wait([
infoFuture,
favoriteFuture,
]);
改成:
scss
final (bookInfo, isFavorite) = await (
infoFuture,
favoriteFuture,
).wait;
这里的两个 Future 仍然会并发执行。
区别在于,Record 可以保留每个位置对应的具体类型。
也就是说:
scss
final (bookInfo, isFavorite) = await (
infoFuture,
favoriteFuture,
).wait;
得到的变量类型分别是:
arduino
bookInfo → BookInfo
isFavorite → bool
不需要再写:
csharp
as BookInfo
as bool
也不需要通过:
css
results[0]
results[1]
访问结果。