是否可以在 Dart 中创建自己的期货以从您的方法返回,或者您必须始终从 dart 异步库方法之一返回内置的未来返回?
我想定义一个函数,它总是返回一个Future<List<Base>>
它是否实际执行异步调用(文件读取/ajax/etc)或只是获取一个局部变量,如下所示:
List<Base> aListOfItems = ...;
Future<List<Base>> GetItemList(){
return new Future(aListOfItems);
}
是否可以在 Dart 中创建自己的期货以从您的方法返回,或者您必须始终从 dart 异步库方法之一返回内置的未来返回?
我想定义一个函数,它总是返回一个Future<List<Base>>
它是否实际执行异步调用(文件读取/ajax/etc)或只是获取一个局部变量,如下所示:
List<Base> aListOfItems = ...;
Future<List<Base>> GetItemList(){
return new Future(aListOfItems);
}
如果您需要创建未来,您可以使用Completer
. 请参阅文档中的Completer
课程。这是一个例子:
Future<List<Base>> GetItemList(){
var completer = new Completer<List<Base>>();
// At some time you need to complete the future:
completer.complete(new List<Base>());
return completer.future;
}
但大多数时候你不需要用完成者来创造未来。就像在这种情况下:
Future<List<Base>> GetItemList(){
var completer = new Completer();
aFuture.then((a) {
// At some time you need to complete the future:
completer.complete(a);
});
return completer.future;
}
使用完成器,代码可能会变得非常复杂。您可以简单地使用以下内容,因为也then()
返回 a Future
:
Future<List<Base>> GetItemList(){
return aFuture.then((a) {
// Do something..
});
}
或文件 io 的示例:
Future<List<String>> readCommaSeperatedList(file){
return file.readAsString().then((text) => text.split(','));
}
有关更多提示,请参阅此博客文章。
您可以简单地使用Future<T>value
工厂构造函数:
return Future<String>.value('Back to the future!');
这个答案是您可以做到的许多方法的总结。
您的方法可以是任何东西,但为了这些示例,假设您的方法如下:
int cubed(int a) {
return a * a * a;
}
目前,您可以像这样使用您的方法:
int myCubedInt = cubed(3); // 27
但是,您希望您的方法返回Future
如下:
Future<int> myFutureCubedInt = cubed(3);
或者能够像这样更实际地使用它:
int myCubedInt = await cubed(3);
以下解决方案都显示了这样做的方法。
最基本的解决方案是使用 的生成构造函数Future
。
Future<int> cubed(int a) {
return Future(() => a * a * a);
}
我将方法的返回类型更改为Future<int>
,然后将旧函数的工作作为匿名函数传递给Future
构造函数。
期货可以以值或错误完成。因此,如果您想明确指定这些选项中的任何一个,您可以使用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);
}
方法会自动async
返回 a Future
,因此您只需标记该方法async
并更改返回类型,如下所示:
Future<int> cubed(int a) async {
return a * a * a;
}
通常你async
与 结合使用await
,但没有什么说你必须这样做。Dart 自动将返回值转换为Future
.
如果您使用另一个Future
在函数体中返回 a 的 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);
}
使用 aCompleter
是最低级别的解决方案。只有当您有一些上述解决方案无法涵盖的复杂逻辑时,您才需要这样做。
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;
}
此示例类似于上面的命名构造函数解决方案。除了以正常方式完成未来之外,它还处理错误。
使用future 并不能保证您不会阻塞UI(即主要隔离)。从你的函数中返回一个未来只是告诉 Dart 将任务安排在事件队列的末尾。如果该任务很密集,当事件循环安排它运行时,它仍然会阻塞 UI。
如果您有一个密集的任务要在另一个隔离区上运行,那么您必须生成一个新的隔离区来运行它。当任务在另一个隔离上完成时,它将返回一条消息作为未来,您可以将其作为函数的结果传递。
许多标准的 Dart IO 类(如File
or HttpClient
)具有将工作委托给系统的方法,因此不会在您的 UI 线程上进行密集工作。因此,这些方法返回的 future 不会阻塞您的 UI。
@Fox32 有正确的答案,除了我们需要提及完成者的类型,否则我们会得到异常
Exception received is type 'Future<dynamic>' is not a subtype of type 'FutureOr<List<Base>>
所以完成者的初始化会变成
var completer= new Completer<List<Base>>();
不完全是给定问题的答案,但有时我们可能想要await
关闭:
flagImage ??= await () async {
...
final image = (await codec.getNextFrame()).image;
return image;
}();
我认为它确实隐含地创造了一个未来,即使我们没有在任何地方传递它。