Dart汇总请点击这里
本文已重新梳理归纳为异步三部曲 请观众老爷移步观看
Future
Future模型是将异步请求和代理模式结合的产物。
Future类是对未来结果的一个代理,它返回的并不是被调用的任务的返回值。
//我的任务
void myTask(){
print("this is my task");
}
void main() {
Future fut = new Future(myTask);//根据我的任务创建Future对象
}
如上代码,Future类实例fut并不是函数myTask的返回值,它只是代理了myTask函数,封装了该任务的执行状态。换种理解方式就是,Future就是一个受你委托的委托人,你将未来要执行的任务交给他,你告知他任务类型是耗时任务,还是非耗时任务,然后分类放到事件循环中去,当任务完成后,它会第一时间执行回调方法告知你任务完成,或者会等到你委托给他的所有任务都完成了立马告知你。
创建Future
Future的几种创建方法
Future()
Future.microtask()
Future.sync()
Future.value()
Future.delayed()
Future.error()
其中sync是同步方法,任务会被立即执行
import 'dart:async';
void main() {
print("main start");
new Future.sync((){
print("sync task");
});
new Future((){
print("async task");
});
print("main stop");
}
运行结果:
main start
sync task
main stop
async task
注册回调
使用then注册回调
当Future中的任务完成后,我们往往需要一个回调,这个回调立即执行,不会被添加到事件队列。
import 'dart:async';
void main() {
print("main start");
Future fut =new Future.value(18);
// 使用then注册回调
fut.then((res){
print(res);
});
// 链式调用,可以跟多个then,注册多个回调
new Future((){
print("async task");
}).then((res){
print("async task complete");
}).then((res){
print("async task after");
});
print("main stop");
}
运行结果:
main start
main stop
18
async task
async task complete
async task after
除了then方法,还可以使用catchError来处理异常,如下
new Future((){
print("async task");
}).then((res){
print("async task complete");
}).catchError((e){
print(e);
});
还可以使用静态方法wait 等待多个任务全部完成后回调。
import 'dart:async';
void main() {
print("main start");
Future task1 = new Future((){
print("task 1");
return 1;
});
Future task2 = new Future((){
print("task 2");
return 2;
});
Future task3 = new Future((){
print("task 3");
return 3;
});
Future fut = Future.wait([task1, task2, task3]);
fut.then((responses){
print(responses);
});
print("main stop");
}
运行结果:
main start
main stop
task 1
task 2
task 3
[1, 2, 3]
如上,wait返回一个新的Future,当添加的所有Future完成时,在新的Future注册的回调将被执行。
async 和 await
在Dart1.9中加入了async和await关键字,有了这两个关键字,我们可以更简洁的编写异步代码,而不需要调用Future相关的API。他们允许你像写同步代码一样写异步代码和不需要使用Future接口。
将 async 关键字作为方法声明的后缀时,具有如下意义
被修饰的方法会将一个 Future 对象作为返回值
该方法会同步执行其中的方法的代码直到第一个 await 关键字,然后它暂停该方法其他部分的执行;
一旦由 await 关键字引用的 Future 任务执行完成,await的下一行代码将立即执行。
// 导入io库,调用sleep函数
import 'dart:io';
// 模拟耗时操作,调用sleep函数睡眠2秒
doTask() async{
await sleep(const Duration(seconds:2));
return "Ok";
}
// 定义一个函数用于包装
test() async {
var r = await doTask();
print(r);
}
void main(){
print("main start");
test();
print("main end");
}
运行结果:
main start
main end
Ok
注意:需要注意,async 不是并行执行,它是遵循Dart 事件循环规则来执行的,它仅仅是一个语法糖,简化Future API的使用。
总结
Future中的then并没有创建新的Event丢到Event Queue中,而只是一个普通的Function Call,在FutureTask执行完后,立即开始执行
当Future在then函数已经执行完成了,则会创建一个task,将该task的添加到microtask queue中,并且该任务将会执行通过then传入的函数
Future只是创建了一个Event,将Event插入到了Event Queue的队尾
Future.value创建Task到microtask Queue中执行then传入的函数
Future.sync执行了它传入的函数之后,也会立即创建Task丢到microtask Queue中执行
Future.wait等待多个任务全部完成后回调。wait返回一个新的Future,当添加的所有Future完成时,在新的Future注册的回调将被执行。
Future.delayed在延时一定时间后向队列插入一个任务
虽然可以预测任务执行的顺序,但是我们无法预测事件循环什么时候会从队列中提取任务。Dart事件处理系统基于单线程循环,而不是基于时基(tick,系统的相对时间单位)或者其他的时间度量。例如,当你创建一个延时1s的任务,1s后向事件队列添加一个任务,但在该任务之前的任务结束前,事件循环是不会处理这个任务的,也就是说该任务执行可能是大于1s的。