java中用thread来支持异步操作,而dart中用的是Future
Future
表示在将来某时获取一个值的方式,本质是等待其他队列完成
基础使用
//执行打印顺序是先a再b
main(){
Future f = Future(() => print("b"));
print("a");
}
我们在Future中使用延迟操作并不影响main线程的其他方法执行,并不会阻塞线程
关键字 async 和 await
main(){
getName1();
getName2();
}
Future<void> getName1() async {
Future(()=>print("===1==="));
await getStr1(); //遇到第一个await表达式执行暂停,返回future对象,await表达式执行完成后继续执行
await Future(()=>print("===2===")); //await表达式可以使用多次
print('getName1');
}
getStr1() {
print('getStr1');
}
getName2() {
print('getName2');
}
打印结果为:
getStr1
getName2
===1===
===2===
getName1
await关键字,会先执行函数,然后返回一个Future对象
await必须在async修饰的函数中才能使用
如果函数没有返回一个有用的值,那么将其返回Future<void>类型
错误处理
main(){
Future(() => 0) // 异步任务的函数
.then((m) => "a$m") // 任务执行完后的子任务
.then((m) => print('显示: $m')) // 其中m为上个任务执行完后的返回的结果
.then((_) => Future.error('error')) //返回错误,上一步未返回m,此步的参数无意义
.then((_) => print('我并不执行'))
.whenComplete(() => print('whenComplete1')) //不是最后执行whenComplete,通常放到最后回调
.catchError((e) => print('catchError:' + e), test: (Object o) {
print('test:' + o);
//return true; //返回true,会被catchError捕获
return false; //返回false,继续抛出错误,会被下一个catchError捕获,自己不做处理
})
.catchError((e) => print(e));//如果不写test默认实现一个返回true的test方法
}
打印结果
显示: a0
whenComplete1
test:error
error
whenComplete和then区别
- whenComplete在上一步报错后仍会执行,而then不会
- whenComplete的闭包函数是无参的,而then的需要传递一个参数
scheduleMicrotask
main(){
Future(() => print("f")); //3. 最后执行
scheduleMicrotask(() => print('s')); //2. 次之
print("a"); // 1. 优先执行
}

这里会建立2个队列,Microtask队列和event队列,Microtask优先于event队列,当Microtask全部执行完后才会执行event
嵌套使用的调用顺序
main(){
Future(() => print('s1'))
.then((_) => Future(() => print('s2')))
.then((_) => print('s3'));
Future(() => print('s4')).then((_) {
print('s5');
scheduleMicrotask(() => print('s6'));
}).then((_) => print('s7'));
}
打印顺序是:
s1
s4
s5
s7
s6
s2
s3
在s1之后的then又创建了一个Future,Future需要当前Zone的Future全部执行完,才会执行下一个。而s3需要在s2执行完毕后才执行,因为需要等待s2那步返回的参数
如果将第一个改为:
//无返回值
Future(() => print('s1'))
.then((_) { Future(() => print('s2'));})
.then((_) => print('s3'));
打印结果
s1
s3
s4
s5
s7
s6
s2
深入分析
内部其实使用的是一个定时任务
factory Future(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
Timer.run(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
我们做一个测试:
main(){
Timer.run(() {
print("c"); // 3
});
scheduleMicrotask(() => print('b')); // 2
print("a"); // 1
}
接着分析一下then:
Future<R> then<R>(FutureOr<R> f(T value), {Function onError}) {
Zone currentZone = Zone.current;
if (!identical(currentZone, _rootZone)) {
f = currentZone.registerUnaryCallback<FutureOr<R>, T>(f);
if (onError != null) {
onError = _registerErrorHandler(onError, currentZone);
}
}
return _thenNoZoneRegistration<R>(f, onError);
}
并未做什么处理,直接追踪 _thenNoZoneRegistration
Future<E> _thenNoZoneRegistration<E>(
FutureOr<E> f(T value), Function onError) {
_Future<E> result = new _Future<E>();
_addListener(new _FutureListener<T, E>.then(result, f, onError));
return result;
}
找到了一个增加监听器的方法,进入查看
void _addListener(_FutureListener listener) {
assert(listener._nextListener == null);
if (_mayAddListener) {
listener._nextListener = _resultOrListeners;
_resultOrListeners = listener;
} else {
if (_isChained) {
_Future source = _chainSource;
if (!source._isComplete) {
source._addListener(listener);
return;
}
_cloneResult(source);
}
assert(_isComplete);
//执行
_zone.scheduleMicrotask(() {
_propagateToListeners(this, listener);
});
}
}
一大段处理后,最终来到scheduleMicrotask方法
factory Future.microtask(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
scheduleMicrotask(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
内部其实还是使用的scheduleMicrotask,创建一个Microtask队列
到此,我们来模拟一下:
main(){
Timer.run(() {
print("b"); // 2
scheduleMicrotask(() => print('c')); // 3
scheduleMicrotask(() => print('d')); // 4
});
Timer.run(() {
print("e"); // 5
});
print("a"); // 1
}
也简单的实现了then的效果
Isolate
为了保持你app的可响应性,大计算量的任务放入额外的isolate中
它是类似于线程(thread)但不共享内存的独立运行的worker,是一个独立的Dart程序执行环境。默认环境main就是一个isolate
官方使用例子:
import 'dart:async';
import 'dart:isolate';
main() async {
var receivePort = new ReceivePort();
await Isolate.spawn(echo, receivePort.sendPort);
//'echo'发送的第一个message,是它的SendPort
//first 是 echo 线程的消息入口
var sendPort = await receivePort.first;
var msg = await sendReceive(sendPort, "foo");
print('received $msg');
msg = await sendReceive(sendPort, "bar");
print('received $msg');
}
/// 新isolate的入口函数
echo(SendPort sendPort) async {
// 实例化一个ReceivePort 打开接收端口以接收消息
var port = new ReceivePort();
// 把它的sendPort发送给宿主isolate,以便宿主可以给它发送消息
sendPort.send(port.sendPort);
// 监听循环接收消息
await for (var msg in port) {
var data = msg[0];
SendPort replyTo = msg[1];
replyTo.send(data);
if (data == "bar") port.close();
}
}
/// 对某个port发送消息,并接收结果
Future sendReceive(SendPort port, msg) {
ReceivePort response = new ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
生成器
当需要延迟地生成一个值序列时,请考虑使用生成器函数
//同步生成器: 使用sync*,返回的是Iterable对象
Iterable<int> getSyncGenerator(int n) sync* {
print('start');
int k = n;
while (k > 0) {
//yield会返回moveNext为true,并等待 moveNext 指令
yield k--;
}
print('end');
}
//异步生成器: 使用async*,返回的是Stream对象
Stream<int> getAsyncGenerator(int n) async* {
print('start');
int k = 0;
while (k < n) {
//yield不用暂停,数据以流的方式一次性推送,通过StreamSubscription进行控制
yield k++;
}
print('end');
}
//递归生成器:使用yield*
Iterable<int> getSyncRecursiveGenerator(int n) sync* {
if (n > 0) {
yield n;
yield* getSyncRecursiveGenerator(n - 1);
}
}
//异步递归生成器
Stream<int> getAsyncRecursiveGenerator(int n) async* {
if (n > 0) {
yield n;
yield* getAsyncRecursiveGenerator(n - 1);
}
}
递归生成器使用方法是一样的
main() {
//同步生成器
//调用getSyncGenerator立即返回Iterable
var it = getSyncGenerator(5).iterator;
// 调用moveNext方法时getSyncGenerator才开始执行
while (it.moveNext()) {
print(it.current);
}
//异步生成器
//调用getAsyncGenerator立即返回Stream,只有执行了listen,函数才会开始执行
// getAsyncGenerator(5).listen((value) => print(value));
StreamSubscription subscription = getAsyncGenerator(5).listen(null);
subscription.onData((value) {
print(value);
if (value >= 2) {
subscription.pause(); //可以使用StreamSubscription对象对数据流进行控制
}
});
print('over');
}
总结:
- Dart事件循环执行两个队列里的事件:event队列和microtask队列
- 事件循环会优先清空microtask队列,然后才会去处理event队列。当两个队列都清空后,dart就会退出
详细可参见:https://webdev.dartlang.org/articles/performance/event-loop