异步编程
Dart可以像C#或Javascript那样可以通过 async/await
实现异步逻辑
Future与async/await
与Js的async/awiat
是Promise
的语法糖一样,Dart的async/awiat
只不过是Future
的语法糖,可以帮助我们的用同步的代码处理Future提高可读性。脱离async/await
,Future本身的API仍然可以完成异步逻辑。
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
await
必须在async{...}
中使用。
async{...}
中使用await可以等待异步完成,但是不会阻塞线程。
await expression
的expression通常是一个Future对象,如果不是则被自动包装成Future,这相对于Javascript更智能。
async
的返回值会被自动包装成Future,例如在main函数使用async,会返回Future<Void>
Future main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
lambda表达式中也可以出现async
Future<String> lookUpVersion() async => '1.0.0';
使用try...catch
处理Future中的异常
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
Stream与async/await
熟悉RxJava的人都知道Stream的概念(流式数据),Dart中的Stream类型也有同样功能:连续多个数据的异步处理。
与Future一样,我们可以通过Stream的API或者通过async/await
进行异步处理。
Stream使用类似循环语句的写法await for
:
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
await for
同样必须出现在 async{...}
。
像循环语句一样,通过return
或者break
可以结束stream处理
await for
只能处理Cold Stream
,即Stream中的数据是有始有终的,对于像Event监听这种没有固定数量的数据(Hot Stream
)处理,无法使用,因为没有从循环外部取消订阅的API。
使用StreamAPI中的listene()
可以得到StreamSubscription
对象用来处理Hot Stream,它具有cancel
方法可以取消订阅。
Generators(生成器)
JavaScript中有类似概念:用来生成Iterable
或者 Stream
的函数。
Stream
相当于异步版本的Iterable
。
- 同步生成器:返回
Iterable
对象
// body前需要加 sync*
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
// yield的地方,暂停执行并通过Itertable返回当前值k
while (k < n) yield k++;
}
- 异步生成器:返回
Stream
对象
用法没有区别,只是sync*
换成async*
,比Javascrip异步生成器方便得多
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
可以通过yield*
提高尾递归的性能:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
并发(Isolate)
Dart没有Thread
,所有代码运行在Isolate
上。
Dart通过启动多Isolate
实现并发编程。
Isolate
相对于Thread
的主要不同在于,Isolate
拥有独立的heap,互相之间不共享资源,隔离程度更接近进程。Isolate
间通信需要通过开Port
,类似socket方式的IPC。
import "dart:isolate";
import "dart:async";
void w(sendPort) {
for(int i = 0; i< 100000; i ++) {
print("waiting: $i");
}
sendPort.send("finished!");
}
main() async {
final receivePort = ReceivePort();
final sendPort = receivePort.sendPort;
await Isolate.spawn(w, sendPort);
receivePort.listen((msg){
print("message from another Isolate: $msg");
});
}
这种IPC式的通信不像线程间通信那样方便,但是安全性更高。
通过Isolate.spawnUri()
可以将main()
中的其他文件在新的Isolate
中执行,Flutter的主进程也是以这种方式启动的。