[TOC]
Dart库中有非常多的函数返回Future对象或Stream对象。这些函数是异步的:在可能耗时的操作(例如I/O)操作的语句之后不等到操作执行完成就返回。
async和await关键字支持异步编程,允许您编写类似于同步代码的异步代码。
## 处理Futures
当你需要一个完整的Futures的结果时,你有两个选择:
* 使用async和await
* 使用Future的API,如[库的引导]中描述的一样
使用async和await的代码虽然是异步的,但是看起来很像同步代码。例如,以下代码使用await来等待异步函数执行的结果:
~~~
await lookUpVersion();
~~~
要使用await必须是对一个使用async标注的异步函数:
~~~
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
~~~
>注意:尽管异步函数可能执行耗时的操作,但它不会等待这些操作。相反,异步函数一直执行直到遇到第一个await表达式([查看详细信息])。然后它返回一个Futures的对象,只有在await表达式完成之后才恢复执行。
>
Use try, catch, and finally to handle errors and cleanup in code that uses await:
使用try,catch和finally来处理使用await的代码中的错误:
~~~
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
~~~
你可以在异步函数中多次使用await。例如,以下代码执行了三次await来获取函数的结果。
~~~
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
~~~
在await表达式中,表达式的值通常是一个Future对象。如果不是,那么这个值将被自动包装成Future。Futrue对象指示返回结果一定是一个对象。表达式的值就是被返回的对象。await表达式会让程序执行挂起,直到返回的对象可用。
***如果在使用await时出现编译时错误,请确保await在异步函数中*** 。例如,要在应用程序的main()函数中使用wait, main()的主体必须标记为async:
~~~
Future main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
~~~
## 声明异步函数
异步函数是函数体被用async修饰符标记的函数。
向函数中添加async关键字将使其返回一个Future。例如,请思考下例中返回一个字符串的同步函数:
~~~
String lookUpVersion() => '1.0.0';
~~~
如果你将他改变成一个异步函数,他的返回值将是一个Future:
~~~
Future<String> lookUpVersion() async => '1.0.0';
~~~
注意,函数的主体不需要使用Future的API。如果需要,Dart将创建Future的对象。
如果您的函数没有返回一个有用的值,那么将其返回Future\<void>类型。
## 处理流(Stream)
当您需要从Stream获取值时,您有两个选择:
* 使用async和异步的for循环(await for)
* 使用Stream API,如[库的引导]中的描述
>注意:在使用await for之前,请确保它使代码更清晰,并且您确实希望等待流(Stream)的所有结果。例如,您通常不应该为UI事件侦听器使用await,因为UI框架会发送无穷无尽的事件流。
>
异步for循环有以下形式:
~~~
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
~~~
表达式的值必须具有Stream类型。执行过程如下:
1. 等待流发出值。
2. 执行for循环的主体,并将变量设置为发出的值。
3. 重复1和2,直到流关闭。
要停止侦听流,您可以使用break或return语句,该语句将跳出for循环,并从流中取消订阅。
如果在实现异步for循环时出现编译时错误,请确保await在异步函数中。例如,要在应用程序的main()函数中使用异步For循环,main()的主体必须标记为async:
~~~
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
~~~
有关异步编程的更多信息,请参阅[库引导文档]的dart:async部分。还可以参阅文章[Dart语言异步支持:阶段1]和[Dart语言异步支持:阶段2]和[Dart语言规范]。