Dart之旅10: 异步支持
dart中充满了返回Future
和Stream
对象的方法。这些方法是异步的:它们设置了一个耗时操作之后就会直接返回,而不是等待操作完成。
async
和await
关键字支持异步编程,并且让你编写看起来像是同步编程一样的代码。
处理Future
当你需要Future的执行结果时,你有两种选择:
- 使用
async
和await
- 使用Future的API,在library tour中有详细描述。
代码使用async
和await
是异步的,但是它看起来像是同步代码。例如,这里有代码使用await
来等待异步方法的结果。
await lookUpVersion();
如果想要使用await
,代码必须使用异步方法——用async
标记的方法:
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
注意:虽然异步方法会执行一个耗时操作,但它不会等待那些操作,一个async方法会执行到第一个await表达式,然后它会返回一个Future对象,用来处理await中操作的结果。
使用try-catch-finally
来对await表达式进行异常处理:
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
你可以在一个方法中多次使用await
:
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
在await表达式中,表达式的值通常是一个Future;如果不是,那么这个将会自动包装在Future中。这个Future对象指代了一个返回对象的约定(类似Java的Future类)。await表达式的值就是那个Future返回的值。await会在Future返回之前阻塞代码的执行。
如果你得到了一个编译时错误,那么你要确保你的await是在async方法中使用的,例如在main方法中使用await就要把main()方法标记为async
:
Future main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
声明异步方法
异步方法需要添加async
修饰符标识。例如你想将下面的函数变成异步方法:
String lookUpVersion() => '1.0.0';
那么你可以这样写:
Future<String> lookUpVersion() async => '1.0.0';
注意方法体内部并没有必要使用Future API,如果有必要的话dart会创建一个Future对象。
如果你的异步方法没有返回一个有用的值,那他会返回类型Future<void>
.
处理流
当你需要处理一个来自Stream的值,那么你有两种选择:
- 使用
async
和一个异步的for循环(await for
)。 - 使用Stream的API
异步for循环的写法如下:
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
expression
的值必须是Stream类型。执行过程如下
- 等待流发射值
- 执行for循环,并将变量设置为流发射的值
- 重复1和2步骤
想要停止监听流,可以使用break
或者return
语句,它们可以跳出for循环,并且取消对流的订阅。
和await
表达式一样await for
也需要函数体使用async
包裹,否则可能会出现编译时错误:
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}