Dart库中包含许多返回 Future 或 Stream 对象的函数。这些函数是异步的:它们在启动一个耗时操作(例如I/O操作)后返回,而不是等待该耗时操作完成。
async 和 await 关键字支持异步编程,它们使你编写异步代码看起来跟编写同步代码一样。
当你需要一个已经完成了的Future对象的结果时,你有两个选择:
使用async 和 await 的代码是异步的,但是看起来像是同步代码。例如,这里的代码使用 await 来等待一个异步函数的结果:
await lookUpVersion();
要使用 await ,代码必须在一个异步函数内部—一个被标记为 async 的函数:
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
注意: 虽然异步函数可能执行耗时的操作,但它不会等待这些操作。相反,异步函数只在遇到第一个await表达式时执行( details )。然后它会返回一个Future对象,尽在 await 表达式完成之后才恢复执行。
在使用 await 的代码处通过 try、catch 和 finally 来处理错误以及清理工作。
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 对象会保证返回一个对象。 await 表达式的值就是那个返回的对象。 await 表达式使得执行暂停,直到结果对象可用。
如果你在使用 await 时出现一个编译时错误,确保 await 是在一个异步函数中。例如,要在你的APP的 main() 函数中使用 await ,那么 main() 函数的函数体必须被标记为 async 。
Future main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
一个异步函数是一个函数体被标记为 async 的函数。
给一个函数添加 async 关键字使它返回一个 Future 。例如,考虑下面这个返回一个字符串的同步函数:
String lookUpVersion() => '1.0.0';
如果你将它改变成异步函数,那么它的返回值是一个 Future。
Future lookUpVersion() async => '1.0.0';
注意,函数的函数体不需要使用 Future API .Dart 会在需要的时候创建 Future 对象。
如果你的函数不需要返回一个有用的值,那么它的返回类型是 Future
当你需要从一个流(Stream)获取值时,你有两个选择:
一个异步 for 循环的格式如下:
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
上面的代码中 expression 的类型必须是 Stream,执行过程如下:
1. 会一直等待直到流发射一个值
2. 使用发射的值作为变量,执行for循环的循环体
3. 重复 1 和 2 ,直到流被关闭
要停止对流的监听,你可以使用一个 break 和 return 语句,它可以终止 for 循环并且解除对流的订阅。
当实现一个异步的for循环时如果出现一个编译时错误,确保 await for 在一个异步函数中。例如,在你的APP的 main() 函数中使用一个异步 for 循环, main() 的函数体必须被标记为 async :
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
关于异步编程的更多信息,请参考:dart:async.
当你需要延迟产生一些数据序列时,使用生成器函数。Dart 支持两种生成器函数:
要实现一个 同步 生成器函数,将函数体标记为 sync* ,并且使用yield 语句来发送数据。
Iterable naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
要实现一个 异步 生成器函数,将函数体标记为 async* ,并且使用 yield 语句来发送数据。
Stream asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
如果你的生成器是递归的,你可以使用 yield* 来提升它的性能:
Iterable naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
要允许像函数一样调用Dart类的实例,实现 call() 方法即可:
class WannabeFunction {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
}
大多数计算机,即使是在移动平台上,都拥有多核心CPU。要充分使用所有的这些核心,开发人员传统上使用共享内存的线程并发执行。然而,共享状态的并发执行容易出错,并且可能导致代码复杂化。
所有Dart代码都在 isolates 中运行,而不是线程。每一个 Isolate 都有它自己的内存堆,这就确保没有任何 Isolate 状态可以被其他任意 isolate 访问。
关于 Isolates 的更多信息, dart:isolate library documentation 。