Future<T>抽象 接口

异步计算的输出结果。

异步计算在启动时不能立即提供结果,这与同步计算不同,同步计算可以通过返回值或抛出异常立即计算结果。异步计算可能需要等待程序外部的事情(读取文件、查询数据库、获取网页)完成,这可能需要时间。异步计算不会在结果可用之前阻塞所有计算,而是立即返回一个将“最终”完成并包含结果的 Future

异步编程

要执行异步计算,您使用一个总是产生未来的 async 函数。在异步函数内部,您可以使用 await 操作延迟执行,直到另一个异步计算有结果。当等待函数执行被延迟时,程序不会阻塞,可以继续做其他事情。

示例

import "dart:io";
Future<bool> fileContains(String path, String needle) async {
   var haystack = await File(path).readAsString();
   return haystack.contains(needle);
}

这里,来自 dart:ioFile.readAsString 方法是一个返回 Future<String> 的异步函数。在 fileContains 函数的函数体之前标记为 async,这意味着您可以在其中使用 await,并且它必须返回一个未来。对 File(path).readAsString() 的调用启动将文件读取为字符串并产生一个将最终包含结果的 Future<String>。然后 await 等待该未来完成(以字符串或错误,如果读取文件失败)。在等待时,程序可以做其他事情。当未来以字符串完成时,fileContains 函数计算一个布尔值并返回它,然后它返回当最初被调用时返回的原始未来。

如果一个未来以一个 错误 完成,等待那个未来将(重新)抛出那个错误。在这里,我们可以添加错误检查

import "dart:io";
Future<bool> fileContains(String path, String needle) async {
  try {
    var haystack = await File(path).readAsString();
    return haystack.contains(needle);
  } on FileSystemException catch (exception, stack) {
    _myLog.logError(exception, stack);
    return false;
  }
}

您使用正常的 try/catch 来捕获等待的异步计算失败。

通常,当编写异步代码时,您应该始终在产生未来时等待它,而不是在其他异步延迟之后等待。这确保了您准备好接收未来可能产生的任何错误,这对于一个无人等待的异步错误来说很重要,因为无人等待的异步错误是一个 未捕获 错误,可能会导致正在运行的程序终止。

使用 Future API 编程。

Future 类还提供了一种更直接、更低级的访问其完成结果的机制。asyncawait 语言特性建立在上述功能之上,有时直接使用它是有意义的。有些事情仅仅通过逐个 await 一个未来是无法完成的。

使用 Future,您可以手动注册回调,以处理值或错误。例如

Future<int> future = getFuture();
future.then((value) => handleValue(value))
      .catchError((error) => handleError(error));

由于 Future 可以以两种方式完成,要么是值(如果异步计算成功),要么是错误(如果计算失败),因此您可以安装针对这两种情况之一的回调。

在某些情况下,我们说一个未来是以另一种方式完成的 另一个未来。这是一种简化的说法,即该未来以与其他未来相同的方式完成,使用相同的值或错误,一旦其他未来完成。平台库中大多数完成未来的函数(例如 Completer.completeFuture.value),也接受另一个未来,并自动处理将结果转发给被完成的未来。

注册回调的结果本身也是一个 Future,它反过来完成调用相应回调的结果。如果调用的回调抛出异常,则新未来以错误完成。例如

Future<int> successor = future.then((int value) {
    // Invoked when the future is completed with a value.
    return 42;  // The successor is completed with the value 42.
  },
  onError: (e) {
    // Invoked when the future is completed with an error.
    if (canHandle(e)) {
      return 499;  // The successor is completed with the value 499.
    } else {
      throw e;  // The successor is completed with the error e.
    }
  });

如果一个未来在以错误完成时没有注册任何处理程序,它将错误转发给“未捕获的错误处理程序”。这种行为确保没有错误被默默忽略。然而,这也意味着错误处理程序应该尽早安装,以便在未来的错误完成时立即存在。以下示例演示了这种潜在的错误

var future = getFuture();
Timer(const Duration(milliseconds: 5), () {
  // The error-handler is not attached until 5 ms after the future has
  // been received. If the future fails before that, the error is
  // forwarded to the global error-handler, even though there is code
  // (just below) to eventually handle the error.
  future.then((value) { useValue(value); },
              onError: (e) { handleError(e); });
});

在注册回调时,通常更易于阅读的是分别注册两个回调,首先使用 then 与一个参数(值处理程序)一起使用,然后使用第二个 catchError 来处理错误。这些都会将它们不处理的任何结果转发给它们的后续程序,并且一起处理值和错误结果。它还有处理 then 值回调中抛出的错误的额外好处。使用顺序处理程序而不是并行处理程序通常会导致易于推理的代码。它还使异步代码非常类似于同步代码

// Synchronous code.
try {
  int value = foo();
  return bar(value);
} catch (e) {
  return 499;
}

基于未来的等效异步代码

Future<int> asyncValue = Future(foo);  // Result of foo() as a future.
asyncValue.then((int value) {
  return bar(value);
}).catchError((e) {
  return 499;
});

类似于同步代码,错误处理程序(通过 catchError 注册)正在处理由 foobar 抛出的任何错误。如果错误处理程序已作为 then 调用的 onError 参数注册,则它不会捕获 bar 调用的错误。

未来可以注册多个回调对。每个后续程序都独立处理,就像它是唯一的后续程序一样。各个后续程序完成的具体顺序是未定义的。

一个未来也可能永远无法完成。在这种情况下,不会调用任何回调。如果可能的话,通常应避免这种情况,除非它被非常清楚地记录。

可用的扩展
注解
  • @vmIsolateUnsendable

构造函数

Future(FutureOr<T> computation())
创建一个包含调用 computation 的结果的未来,该调用是异步的,使用 Timer.run
factory
Future.delayed(Duration duration, [FutureOr<T> computation()?])
创建一个在延迟后执行其计算的异步操作。
factory
Future.error(Object error, [StackTrace? stackTrace])
创建一个以错误结束的异步操作。
factory
Future.microtask(FutureOr<T> computation())
创建一个包含调用 computation 的异步结果的异步操作。
factory
Future.sync(FutureOr<T> computation())
返回一个包含立即调用 computation 的结果的异步操作。
factory
Future.value([FutureOr<T>? value])
创建一个完成于 value 的异步操作。
factory

属性

hashCode int
此对象的哈希码。
no setterinherited
runtimeType Type
对象的运行时类型的表示。
no setterinherited

方法

asStream() Stream<T>
创建一个包含此异步操作结果的 Stream
catchError(Function onError, {bool test(Object error)?}) Future<T>
处理此 Future 发出的错误。
noSuchMethod(Invocation invocation) → dynamic
当访问不存在的方法或属性时调用。
inherited
then<R>(FutureOr<R> onValue(T value), {Function? onError}) Future<R>
注册当此异步操作完成时调用的回调函数。
timeout(Duration timeLimit, {FutureOr<T> onTimeout()?}) Future<T>
timeLimit 时间后停止等待此异步操作。
toString() String
此对象的字符串表示形式。
inherited
whenComplete(FutureOr<void> action()) Future<T>
注册当此异步操作完成时调用的函数。

操作符

operator ==(Object other) bool
等于操作符。
inherited

静态方法

any<T>(Iterable<Future<T>> futures) Future<T>
返回 futures 中第一个完成的异步操作的结果。
doWhile(FutureOr<bool> action()) Future<void>
重复执行操作直到返回 false
forEach<T>(Iterable<T> elements, FutureOr action(T element)) Future<void>
依次为可迭代对象的每个元素执行一个操作。
wait<T>(Iterable<Future<T>> futures, {bool eagerError = false, void cleanUp(T successValue)?}) Future<List<T>>
等待多个future完成并收集其结果。