在Flutter开发中,一般使用Future、Stream、async/wait使用异步操作。 Future类用于异步任务、Stream类主要用文件IO, 而async/wait是关键字。
官方介绍:Dart消息循环 https://webdev.dartlang.org/articles/performance/event-loop
打开future.dart可以看到Future抽象类依赖Timer抽象类, 而Timer抽象类又依赖Zone抽象类(zone.dart)。 Future是对Timer类的封装, 而Timer类又是对Zone类的封装。 注意这3个类的关系是依赖,而不是继承。在Flutter开发中,也可以直接使用Timer或者Zone实现异步任务。
factory Future(FutureOr computation()) {
_Future result = new _Future();
Timer.run(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
值得注意的是用户输入、Timer、点击事件运行在一个线程中( 即Main isolate)。 Dart消息队列的特点有2个队列, 即event queue和microtask queue。
event queue:包括IO、鼠标事件、绘制事件、定时器、dart isolate之间的消息等等;Futter添加的异步任务都就是向event queue里添加。
microtask:可以理解为拦截器,优先级比event queue要高。 即microtask里的任务必须执行完后,才能执行event queue。
为了加深对Futter的理解, 先看一段代码:
void main() {
print("this is dart entrance");
Future future1 = new Future(() => null);
future1.then((_) {
print("future1 then");
}).catchError((e) {
print("future1 catchError");
}).whenComplete(() {
print("future1 whenComplete");
});
Future future2 = new Future((){
print("future2 init");
});
future2.then((_) {
print("future2 then");
future1.then((_){
print("future1 excute by future2");
});
}).catchError((e) {
print("future2 catchError");
}).whenComplete(() {
print("future2 whenComplete");
});
future1.then((_) {
print("future1 reexecute");
});
Future future3 = new Future((){
print("future3 init");
});
print("this is dart end");
}
运行结果:
this is dart entrance
this is dart end
future1 then
future1 whenComplete
future1 reexecute
future2 init
future2 then
future2 whenComplete
future1 excute by future2
future3 init
原理解释:
1、main方法执行完成后,才能执行event queue里的定时器。 所以最先打印前2句。
2、为什么“future1 reexecute”先于future2? 请注意Future的构造函数, 在实例化Future对象时已经向event queue里新增了一个Timer,执行then只是设置回调函数。 总结一下:一个Future可以注册多个then、delay等回调; Future的执行时序是按照Future实例化的先后顺序执行的。
3、为什么"future1 execute by future2"执行在“future3 init”之前? 请看then函数的注释, 在futurer2的then执行时, future1已经结束了,即event loop正在处理future2。再次调用future1.then会将timer添加到microtask, 这时microtask优先于event queue里的future3, 所以先打印了"future1 execute by future2"。
* When this future completes with a value,
* the [onValue] callback will be called with that value.
* If this future is already completed, the callback will not be called
* immediately, but will be scheduled in a later microtask.
4、then是Future注册的回调函数, 如果Future已经完成(即event loop处理它后面的event),那么会在microtask里调度执行。
catchError是then函数里抛出异常后被捕获。
whenComplete是最后执行的。
为了加深理解,Future的then/catchError/whenComplete执行时序同Java的try/catch/finally。 catchError不一定执行,但whenComplete肯定是最后执行。
在业务开发中可能碰到这个场景, 多个网络接口api都返回后才能刷新UI, 即等待若干个异步任务全部结束后触发某个行为, 这时可以使用Future.wait函数。
* Waits for multiple futures to complete and collects their results.
*
* Returns a future which will complete once all the provided futures
* have completed, either with their results, or with an error if any
* of the provided futures fail.
Future future3 = new Future((){
print("future3 init");
return "future3";
});
print("this is dart end");
Future.wait([
Future.delayed(new Duration(seconds: 1), () {
print("do something1");
return "hello world";
}),
future3,
Future.delayed(new Duration(seconds: 1), () {
print("do something2");
return "hello world2222";
})
]).then((results) {
print(results);
}).catchError((e) {
print(e);
});
在wait里可以执行多个Future, 待全部执行完成后执行then。
do something1
do something2
[hello world, future3, hello world2222]