前言
- 首先
Dart
是单线程的 - 开发中肯定会遇到很多耗时操作的,而单线程肯定不能一直在等待这些耗时操作完成,而造成阻塞
- 那么
Dart
里是如何处理的呢,答:Dart是基于单线程加事件循环来完成耗时操作的处理的
事件循环
-
将需要处理的事件,放到一个事件队列中,不断的从队列中取出对应的事件,并执行。
-
跟咱
iOS
里的Runloop
类似
引用一下官方图,齿轮就是事件循环,不断的从左边取事件执行
image.png
-
实际上
Dart
从两个队列执行任务:event
事件队列和microtask
微任务队列; -
而微任务队列的优先级要高于事件队列;
-
所以是优先执行微任务队列中的任务,再执行 事件队列 中的任务
-
一般来说,I/O事件,手势,Timer,绘制,其他外部事件都会放到
event
事件队列中,而微任务通常来源于Dart
内部,并且很少,因为如果微任务太多,可能会阻塞事件队列,而导致一些用户操作可能就没有反应了。 -
两个队列都是按照先进先出的顺序执行任务
Dart的异步操作
- 主要使用
Future
以及async
、await
首先先举个栗子,看一下同步的耗时操作
void main() {
print('start ${DateTime.now()}');
print('${sendRequest()} ${DateTime.now()}');
print('end ${DateTime.now()}');
}
String sendRequest(){
sleep(Duration(seconds: 2));
return 'Request finish';
}
毫无疑问,sendRequest
会阻塞main
函数的执行,可以看到打印start
和Request finish
之间相隔了2秒

使用Future
void main() {
print('start ${DateTime.now()}');
print('${sendRequest()} ${DateTime.now()}');
print('end ${DateTime.now()}');
}
Future<String> sendRequest(){
return Future<String>((){
sleep(Duration(seconds: 2));
return 'Request finish';
});
}
你会看到,sendRequest
丝毫没有阻塞main
函数的执行,直接连续print
了3次,显然这才是我们需要的效果,但是打印的是一个Future实例,那么我们需要拿到最终的结果。

获取Future结果
- 通过.then的回调
void main() {
print('start ${DateTime.now()}');
print('${sendRequest().then((value){
print('$value ${DateTime.now()}');
})} ${DateTime.now()}');
print('end ${DateTime.now()}');
}

执行异常捕获
void main() {
print('start ${DateTime.now()}');
print('${sendRequest().then((value){
print('$value ${DateTime.now()}');
}).catchError((error){
print('$error ${DateTime.now()}');
})} ${DateTime.now()}');
print('end ${DateTime.now()}');
}
Future<String> sendRequest(){
return Future<String>((){
sleep(Duration(seconds: 2));
//return 'Request finish';
throw Exception('出异常了');
});
}

Future的链式调用
- 可以在
then
中继续return
,可以在下一个then
中拿到结果
void main() {
sendRequest().then((value) {
print('11 - $value ${DateTime.now()}');
return '海贼·王路飞';
}).then((value) {
print('22 - $value ${DateTime.now()}');
return '三刀·流索隆';
}).then((value) {
print('33 - $value ${DateTime.now()}');
});
}
Future<String> sendRequest(){
return Future<String>((){
sleep(Duration(seconds: 2));
return 'Request finish';
});
}

其他
-
Future.value
:返回一个指定值的Future
void main() {
print('start');
Future.value('王路飞').then((value) {
print('$value');
});
print('end');
}

-
Future.error
:返回一个异常的 Future
void main() {
print('start');
Future.error(Exception('异常了')).then((value) {
print('$value');
});
print('end');
}

-
Future.delayed
:延迟执行
void main() {
print('start ${DateTime.now()}');
Future.delayed(Duration(seconds: 2)).then((value) {
print('delayed ${DateTime.now()}');
});
print('end ${DateTime.now()}');
}

当然还有很多
api
,可以自行了解
await、async
- 是
Dart
中的关键字,async
声明函数内部有代码需延迟执行,await
声明运算为延迟执行 -
async
的函数需要返回一个Future
,await
需在async
函数中使用 - 实际上是Dart异步编程用于简化异步API操作的,能够将异步的代码使用同步的代码结构实现
举个栗子,如下,sleepTime
的结果,我在sendRequest
里需要拼接一个a
给出去,可能如下写法
void main() {
print('start ');
print(sendRequest().then((value) {
print(value);
}));
print('end ');
}
Future sendRequest() {
final a = ' 12345';
return sleepTime().then((value) {
return value+a;
});
}
///假设异步耗时请求
Future sleepTime(){
return Future((){
sleep(Duration(seconds: 2));
return 'request finish';
});
}
如果用await,async来写 看看
void main() {
print('start ');
print(sendRequest().then((value) {
print(value);
}));
print('end ');
}
Future sendRequest() async{
final a = ' 12345';
var result = await sleepTime();
return result + a;
}
///假设异步耗时请求
Future sleepTime(){
return Future((){
sleep(Duration(seconds: 2));
return 'request finish';
});
}
- 这样可以像写同步代码一样去使用
Future
异步返回的结果
任务执行顺序
- 顺序:
main函数 -> 微任务队列(Microtask Queue)-> 事件队列(Event Queue)
- 可以通过
scheduleMicrotask
创建一个微任务,Future
是加到事件队列 - 那么来看看执行顺序
void main() {
Future(() => print("event task"));
print('start ');
scheduleMicrotask((){
print('scheduleMicrotask');
});
print('end ');
}

- 可以看到main函数里的
start
和end
先打印了,然后打印了微任务scheduleMicrotask
,最后打印了event task
。
Future代码的加入队列
Future
代码分为构造函数的函数体和(.then/.catchError等
)
-
Future
构造函数的函数体是放在事件队列中 -
.then
的函数体分成几种情况
-
.then
函数体会跟着构造函数体放进事件队列 -
Future
链式调用,.then
函数体会依次放入事件队列 -
Future
里或者.then
里使用微任务,微任务会在Future
完成后才调用
来分析一个复杂的情况,彻底搞清楚任务执行顺序
void main() {
print("main start");
Future(() => print("task1"));
final future = Future(() => null);
Future(() => print("task2")).then((_) {
print("task3");
scheduleMicrotask(() => print('task4'));
}).then((_) => print("task5"));
future.then((_) {
print('task6');
Future(() => print('task7')).then((value) {
Future(() => print('task8'));
});
}).then((value) {
print('task9');
});
scheduleMicrotask(() => print('task10'));
Future(() => print('task11')).then((_) {
Future(() => print('task12')).then((value) {
Future(() => print('task13'));
});
}).then((_) => print('task14'));
Future(() => print('task15'));
print("main end");
}

用下面的图,捋了一下。

从图中可以梳理出打印顺序为:
- `main start`
- `main end`
- `task10`
- `task1`
- `task6`
- `task9`
- `task2`
- `task3`
- `task5`
- `task4`
- `task11`
- `task14`
- `task15`
- `task7`
- `task12`
- `task8`
- `task13`
与实际打印结果一致
isolate
- 我们知道
Dart
是单线程的,在Dart
中其实有个专门名词叫isolate(隔离) -
Flutter
中就有一个Root isolate
, 在Root isolate
内部运行一个EventLoop
事件循环 - 用官方的话来说
isolate
就是一个隔离的Dart
执行上下文 - Dart是支持多个
isolate
的,isolate
之间不共享任何资源,只能依靠消息机制通信 - 如果确实有非常耗时的操作,可以自己创建
isolate
创建isolate
void main() {
print(Isolate.current.hashCode);
Isolate.spawn(testIsolate, "new Isolate");
}
void testIsolate(String msg) {
print("新的isolate:$msg - ${Isolate.current.hashCode}");
}
通信
void main() {
print(Isolate.current.hashCode);
// 创建管道
ReceivePort receivePort= ReceivePort();
Future iso = Isolate.spawn(testIsolate, receivePort.sendPort,debugName: '哈哈哈');
iso.then((value) {
receivePort.listen((data) {
print('receiveData:$data');
//关闭管道
receivePort.close();
// 杀死isolate
value.kill(priority: Isolate.immediate);
});
});
}
void testIsolate(SendPort port) {
print("新的isolate - ${Isolate.current.debugName} ${Isolate.current.hashCode}");
port.send("Hello World");
}

compute(Flutter对Isolate的封装,需要在Flutter中使用)
@override
Widget build(BuildContext context) {
testCompute();
return MaterialApp(
home: Container(),
);
}
void testCompute() async {
String result = await compute(sendMesg, '哈哈哈');
print('$result');
}
static String sendMesg(String msg) {
print(msg);
return '收到了- 回你'+msg;
}
网友评论