从你自己的函数返回一个未来
这个答案总结了你可以做到的许多方法。
起点
您的方法可以是任何东西,但为了这些示例,假设您的方法如下:
int cubed(int a) {
return a * a * a;
}
目前你可以像这样使用你的方法:
int myCubedInt = cubed(3); // 27
但是,您希望您的方法返回 Future,如下所示:
Future<int> myFutureCubedInt = cubed(3);
或者能够像这样更实际地使用它:
int myCubedInt = await cubed(3);
以下解决方案都显示了这样做的方法。
解决方案 1:Future() 构造函数
最基本的解决方案是使用Future的生成构造函数。
Future<int> cubed(int a) {
return Future(() => a * a * a);
}
我将方法的返回类型更改为Future<int>,然后将旧函数的工作作为匿名函数传递给Future构造函数。
解决方案 2:Future 命名构造函数
Futures 可以完成一个值或一个错误。因此,如果您想明确指定这些选项中的任何一个,您可以使用 Future.value 或 Future.error 命名构造函数。
Future<int> cubed(int a) {
if (a < 0) {
return Future.error(ArgumentError("'a' must be positive."));
}
return Future.value(a * a * a);
}
不允许a 使用负值是一个人为的示例,用于展示Future.error 构造函数的使用。如果没有什么会产生错误,那么您可以像这样简单地使用 Future.value 构造函数:
Future<int> cubed(int a) {
return Future.value(a * a * a);
}
解决方案 3:异步方法
async 方法会自动返回 Future,因此您只需标记方法 async 并更改返回类型,如下所示:
Future<int> cubed(int a) async {
return a * a * a;
}
通常您将async 与await 结合使用,但没有任何内容表明您必须这样做。 Dart 自动将返回值转换为Future。
如果您使用另一个在函数体中返回 Future 的 API,您可以像这样使用 await:
Future<int> cubed(int a) async {
return await cubedOnRemoteServer(a);
}
或者这是使用Future.then 语法的同一件事:
Future<int> cubed(int a) async {
return cubedOnRemoteServer(a).then((result) => result);
}
解决方案 4:完成者
使用Completer 是最低级别的解决方案。只有当您有一些上述解决方案无法涵盖的复杂逻辑时,您才需要这样做。
import 'dart:async';
Future<int> cubed(int a) async {
final completer = Completer();
if (a < 0) {
completer.completeError(ArgumentError("'a' must be positive."));
} else {
completer.complete(a * a * a);
}
return completer.future;
}
此示例类似于上面的命名构造函数解决方案。除了以正常方式完成未来之外,它还处理错误。
关于阻止 UI 的说明
使用future 并不能保证您不会阻塞UI(即主隔离)。从你的函数返回一个未来只是告诉 Dart 将任务安排在event queue 的末尾。如果该任务很密集,当事件循环安排它运行时,它仍然会阻塞 UI。
如果您想要在另一个隔离区上运行一项密集型任务,那么您必须生成一个新的隔离区来运行它。当任务在另一个隔离上完成时,它将返回一条消息作为未来,您可以将其作为函数的结果传递。
许多标准的 Dart IO 类(如 File 或 HttpClient)都有将工作委托给系统的方法,因此不会在您的 UI 线程上进行大量工作。因此,这些方法返回的 future 不会阻塞您的 UI。
另见