dart ,如何创造未来回归在自己的功能?

0mkxixxg  于 2022-12-16  发布在  其他
关注(0)|答案(6)|浏览(111)

是否可以在Dart中创建自己的future以从您的方法返回,或者必须始终从dart异步库方法之一返回内置的future返回?
我想定义一个函数,无论它实际上是在执行异步调用(file read/ AJAX /etc)还是只是获取一个局部变量,它总是返回一个Future<List<Base>>,如下所示:

List<Base> aListOfItems = ...;

Future<List<Base>> GetItemList(){

    return new Future(aListOfItems);

}
57hvy0tb

57hvy0tb1#

如果你需要创造未来,你可以使用Completer。请参阅文档中的Completer class。下面是一个例子:

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()也返回一个Future

Future<List<Base>> GetItemList(){
  return aFuture.then((a) {
    // Do something..
  });
}

或者文件io的示例:

Future<List<String>> readCommaSeperatedList(file){
  return file.readAsString().then((text) => text.split(','));
}

更多提示请参见this blog post

v9tzhpje

v9tzhpje2#

您可以简单地使用Future<T>value工厂构造函数:

return Future<String>.value('Back to the future!');
avwztpqn

avwztpqn3#

从自己的函数返回未来

这个答案总结了你可以做的许多方法。
开始点
你的方法可以是任何东西,但为了这些例子,让我们假设你的方法如下:

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可以用一个值或一个错误来完成,因此如果你想显式地指定这两个选项中的任何一个,你可以使用Future.valueFuture.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;
}

通常情况下,您可以将asyncawait结合使用,但没有任何规定必须这样做。Dart会自动将返回值转换为Future
如果您使用的另一个API在函数体中返回一个Future,则可以按如下方式使用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(即主隔离),从函数返回future只是告诉Dart在event queue结束时调度任务,如果任务是密集型的,当事件循环调度它运行时,它仍然会阻塞UI。
如果您有一个密集型任务要在另一个分离菌株上运行,则必须生成一个新的分离菌株来运行它。当在另一个分离菌株上完成任务时,它将返回一条消息作为future,您可以将其作为函数的结果传递。
许多标准的Dart IO类(如FileHttpClient)都有将工作委托给系统的方法,因此这些方法不会在UI线程上执行密集的工作,因此这些方法返回的future不会阻塞UI。

另见

v6ylcynt

v6ylcynt4#

@Fox32有正确的答案,此外,我们需要提到完成者的类型,否则我们会遇到异常
Exception received is type 'Future<dynamic>' is not a subtype of type 'FutureOr<List<Base>>
因此完成器初始化将变为
var completer= new Completer<List<Base>>();

6ju8rftf

6ju8rftf5#

不完全是给定问题的答案,但有时我们可能想await一个闭包:

flagImage ??= await () async {
      ...
      final image = (await codec.getNextFrame()).image;
      return image;
    }();

我认为它确实含蓄地创造了一个未来,尽管我们没有把它传递到任何地方。

dly7yett

dly7yett6#

这里有一个简单的条件式Future的例子。

String? _data;
Future<String> load() async {
    // use preloaded data
    if (_data != null) return Future<String>.value(_data);
    // load data only once
    String data = await rootBundle.loadString('path_to_file');
    _data = data;
    return data;
}

相关问题