Future<T>抽象 接口

异步计算的 结果。

与同步计算不同,异步计算在启动时不能立即提供一个结果,因为同步计算可以直接通过返回一个值或抛出错误来立即得到结果。异步计算可能需要等待程序外部的事情完成(如读取文件、查询数据库、获取网页)这需要时间。为了不阻塞所有计算直到结果可用,异步计算将立即返回一个 Future,该 Future 最终将以结果的方式 "完成"。

异步编程

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

示例

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

这里 File.readAsString 方法从 dart:io 是一个异步函数,返回一个 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 语言特性建立在上述功能之上,有时直接使用它是有意义的。有些事情单靠等待一个未来的方式是无法做到的。

使用一个 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 值回调中处理错误的 catchError。与并行处理程序相比,使用顺序处理程序通常会导致更易于推理的代码。它还使异步代码非常类似于同步代码

// 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 的结果的未来。
factory
Future.delayed(Duration duration, [FutureOr<T> computation()?])
创建一个在延迟后运行计算的未来。
factory
Future.error(Object error, [StackTrace? stackTrace])
创建一个以错误结束的Future。
factory
Future.microtask(FutureOr<T> computation())
异步调用computation并使用scheduleMicrotask创建一个包含结果的Future。
factory
Future.sync(FutureOr<T> computation())
返回一个立即调用computation的结果的Future。
factory
Future.value([FutureOr<T>? value])
创建一个以value完成的Future。
factory

属性

hashCode int
该对象的哈希码。
无getter继承
runtimeType Type
对象的运行时类型的表示。
无getter继承

方法

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

操作符

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

静态方法

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完成并收集它们的结果。