异步计算的 结果。
与同步计算不同,异步计算在启动时不能立即提供一个结果,因为同步计算可以直接通过返回一个值或抛出错误来立即得到结果。异步计算可能需要等待程序外部的事情完成(如读取文件、查询数据库、获取网页)这需要时间。为了不阻塞所有计算直到结果可用,异步计算将立即返回一个 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
类还提供了一种更直接、更低级别的功能来访问它完成的结果。async
和 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 值回调中处理错误的 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 注册)正在处理由 foo
或 bar
抛出的任何错误。如果错误处理程序已作为 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< ) → Future<void> action()T> - 注册一个在异步完成后将被调用的函数。
操作符
-
operator ==(
Object other) → bool - 等于操作符。继承
静态方法
-
any<
T> (Iterable< ) → Future<Future< > futuresT> T> - 返回
futures
中第一个完成的异步的结果。 -
doWhile(
FutureOr< ) → Future<bool> action()void> - 重复执行操作直到它返回
false
。 -
forEach<
T> (Iterable< FutureOr action(T element)) → Future<T> elements,void> - 依次对可迭代对象的每个元素执行一个操作。
-
wait<
T> (Iterable< Future< futures, {bool eagerError = false, void cleanUp(T successValue)?}) → Future<T> >List< T> > - 等待多个future完成并收集它们的结果。