我们知道dart
是一门单线程的语言,那么在遇到网络获取数据
,写入数据库
,从文件读取数据
等操作时,我们怎么来处理呢?
其实dart
是支持异步
操作的,可以使用Future
类和async
和await
关键字
事件循环 event loop
在dart
中有两种队列
- 1.
event queue
(事件队列)属于普通的事件队列,包含所有的外来事件:I/O
、mouse events
、drawing events
、timers
、isolate
之间的信息传递 - 2.
microtask queue
(微任务队列)表示一个短时间内就会完成的异步任务。它的优先级最高,高于event queue
,只要队列中还有任务,就可以一直霸占着事件循环。microtask queue
添加的任务主要是由 Dart内部产生。
在每一次事件循环中,系统会优先去microtask queue
中查询是否有可执行的任务,如果没有,才会处理event queue
并且我们平时执行的任务绝大多数都是在event queue
中执行的,Dart
为event queue
的任务建立提供了一层封装,就是我们经常用到的Future
- 1.声明一个
Future
时,Dart
会将异步任务的函数放入event queue
,然后立即返回,后续代码继续同步执行 - 2.当同步执行的代码执行完毕时,
event queue
会按照加入event queue
的顺序,依次取出事件,最后同步执行Future
的函数体及后续操作
Future
Future<T>
类,其表示一个 T
类型的异步操作结果。如果异步操作不需要结果,则类型为 Future<void>
。也就是说首先Future
是个泛型类,可以指定类型。如果没有指定相应类型的话,则Future
会在执行动态的推导类型。
async
和await
默认的Future是异步运行的。如果想要我们的Future同步执行,可以通过async和await关键字:
void main() {
getData();
print('做点其他事情');
}
String _data = '0';
getData() async {
print('开始获取data=$_data');
//1.后面的操作必须是异步才能使用await修饰
//2.当前函数也必须是async修饰的函数
await Future((){
for (int i = 0; i < 10000000; i++) {
_data = '网络数据';
}
});
print('结束data=$_data');
}
//打印结果
// flutter: 开始获取data=0
// flutter: 做点其他事情
// flutter: 结束data=网络数据
从打印结果可以看出,Future
已经同步执行了。await
会等待Future
执行结束后,才会继续执行后面的代码。
-
async
:用来表示函数的异步的,定义的函数会返回一个Future
对象。 -
await
:后面跟着一个Future
,表示等待该异步任务完成后才会继续往下执行。await
只能出现在异步函数内部
。能够让我们可以像写同步代码那样来执行异步任务而不使用回调的方式。
⚠️注意:
async/await
都只是一个语法糖,编译器或解释器最终都会将其转化为一个Promise(Future)
的调用链
Future
简单使用
- 1.Future.value()
创建一个返回指定value值的Future:
void main() {
futureValueDemo();
}
futureValueDemo() async{
var future = await Future.value(1);
print('future value = $future');//打印结果1
}
- 2.Future.delayed()
创建一个延迟执行的Future:
void main() {
futureDelayedDemo();
print("futureDelayedDemo()执行之后打印。");
}
futureDelayedDemo() async {
//延迟执行2s
Future.delayed(Duration(seconds: 2), () {
print("Future.delayed 2 seconds.");
});
}
- 3.处理Future的结果
对于Future
来说,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future
只会对应一个结果,要么成功,要么失败。
Future的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用。
Dart
提供了下面三个方法用来处理Future的结果。
Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
Future<T> catchError(Function onError, {bool test(Object error)});
Future<T> whenComplete(FutureOr action());
1.Future.then()
用来注册一个Future完成时要调用的回调。如果 Future 有多个then,它们也会按照链接的先后顺序同步执行,同时也会共用一个event loop。
futureThenDemo() async {
Future.value(1).then((value) {
return Future.value(value+1);
}).then((value) {
return Future.value(value+2);
}).then((value) {
print(value); //输出4
});
}
futureThenDemo() async {
int data = 1;
Future future = Future((){
data += 2;
});
Future((){
data += 3;
});
//这里在future执行完成后立即会被执行,优先于 Future((){
// data += 3;
// });
future.then((value) {
print('data=$data');//输出3
});
}
2.Future.catchError()
注册一个回调,来捕捉Future的error:
void testFuture() async {
new Future.error('Future 发生错误啦!').catchError(print, test: (error) {
return error is String;
});
}
then中的回调onError和Future.catchError
Future.catchError回调只处理原始Future抛出的错误,不能处理回调函数抛出的错误,onError只能处理当前Future的错误:
void testFuture() async {
Future.error('Future 发生错误啦!').then((_) {
throw 'new error';
}).catchError((error) {
print('error: $error');
throw 'new error2';
}).then(print, onError:(error) {
print("handle new error: $error"); //输出handle new error: new error2
});
}
3.Future.whenComplete()
Future.whenComplete 在Future完成之后总是会调用,不管是错误导致的完成还是正常执行完毕。比如在网络请求前弹出加载对话框,在请求结束后关闭对话框。并且返回一个Future对象:
void testFuture() async {
var random = new Random();
Future.delayed(new Duration(seconds: 1), () {
if (random.nextBool()) {
return 'Future 正常';
} else {
throw 'Future 发生错误啦!';
}
}).then(print).catchError(print).whenComplete(() {
print('Future whenComplete!');
});
}
//输出
// flutter: Future 正常
// flutter: Future whenComplete!
最后
通过这篇文章我们了解了Dart中的事件循环和event queue和microtask queue之间关系。同时,介绍了一些关于Dart Future的一些基础使用和高级用法,同时穿插了一些使用实例,用来帮助大家更好的来理解Dart中的异步操作。