异步计算的输出结果。
异步计算在启动时不能立即提供结果,这与同步计算不同,同步计算可以通过返回值或抛出异常立即计算结果。异步计算可能需要等待程序外部的事情(读取文件、查询数据库、获取网页)完成,这可能需要时间。异步计算不会在结果可用之前阻塞所有计算,而是立即返回一个将“最终”完成并包含结果的 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:io
的 File.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
类还提供了一种更直接、更低级的访问其完成结果的机制。async
和 await
语言特性建立在上述功能之上,有时直接使用它是有意义的。有些事情仅仅通过逐个 await
一个未来是无法完成的。
使用 Future,您可以手动注册回调,以处理值或错误。例如
Future<int> future = getFuture();
future.then((value) => handleValue(value))
.catchError((error) => handleError(error));
由于 Future 可以以两种方式完成,要么是值(如果异步计算成功),要么是错误(如果计算失败),因此您可以安装针对这两种情况之一的回调。
在某些情况下,我们说一个未来是以另一种方式完成的 另一个未来。这是一种简化的说法,即该未来以与其他未来相同的方式完成,使用相同的值或错误,一旦其他未来完成。平台库中大多数完成未来的函数(例如 Completer.complete 或 Future.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 注册)正在处理由 foo
或 bar
抛出的任何错误。如果错误处理程序已作为 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< futures) → Future<T> >T> - 返回
futures
中第一个完成的异步操作的结果。 -
doWhile(
FutureOr< bool> action()) → Future<void> - 重复执行操作直到返回
false
。 -
forEach<
T> (Iterable< T> elements, FutureOr action(T element)) → Future<void> - 依次为可迭代对象的每个元素执行一个操作。
-
wait<
T> (Iterable< Future< futures, {bool eagerError = false, void cleanUp(T successValue)?}) → Future<T> >List< T> > - 等待多个future完成并收集其结果。