Dart是一个在单线程中运行的程序,如果遇到一个耗时的操作,程序将会被冻结。为了避免这种情况,可以使用一个异步操作使程序在等待耗时操作时完成时继续处理其他操作。在Dart中,可以使用Future对象来表示异步操作的结果。
1、Dart的消息循环机制

Dart中有一个事件循环(Event Loop) 来执行我们的代码,里面存在一个事件队列(Event Queue),事件循环不断从事件队列中取出事件执行。
1.1、微任务队列
- 微任务队列的优先级要高于事件队列
- 事件循环优先执行微任务队列中的任务,再执行事件队列中的任务
- 所有的外部事件任务都在事件队列中,如:IO、计时器、点击、绘制事件
- 微任务通常来源于
Dart内部,并且微任务非常少
在Dart的单线程中,代码执行顺序是怎样的呢?
1、Dart的入口函数是main函数,所以main函数中的代码会优先执行
2、main函数执行完成后,会启动一个事件循环(Event Loop),启动后开始执行队列中的任务
3、首先,会按照先进先出的顺序,执行 微任务队列(Microtask Quene) 中的所有任务
4、其次,会按照先进先出的顺序,执行 事件队列(Event Quene) 中的所有任务
1.2、创建微任务
在开发中,如果我们有一个任务不希望它放在Event Quene中排队,那么就可以创建一个微任务
我们可以通过dart中async下的scheduleMicrotask来创建一个任务
import "dart:async";main(List<String> args) {scheduleMicrotask(() {print("Hello Microtask");});}
1.2.1、Future 的代码是加入微任务队列还是事件队列?
Future中通常有两个函数执行体:
Future构造函数传入的函数体then函数的函数体
那么它们是加入到什么队列中呢?
Future的构造函数传入的函数体放事件队列中then的函数体分以下几种情况:
1、Future没有执行完成,then函数会被添加到Futue函数执行体后
2、Future执行完成后执行then,then函数体被放到微任务队列,当前Future执行完成后再执行微任务队列
3、如果Future是链式调用,则当前then函数体未执行完成,下一个then不会执行
2、async/await
Flutter是一个单线程并且跑着一个event loop,因此不必担心线程管理。如果你正在做I/O操作,可以安全地使用async/await来完成。如果需要让CPU执行繁忙的计算密集型任务,就需要使用Isolate来避免阻塞event loop。
对于I/O操作,通过关键字async把方法声明为异步方法,然后通过await关键字等待该异步方法执行完成:
loadData() async {String url = "https://xxxx";http.Response response = await http.get(url);setState(() {widgets = json.decode(response.body);});}
3、Isolate
Isolate是分离的运行线程,并且不和主线程的内存堆共享内存。这意味着你不能访问主线程中的变量,或者使用setState()来更新UI,Isolate不能共享内存,每个lsolate都有自己的Event Loop与Quene。
下面是简单的Isolate的简单用法,把数据返回给主线程更新UI:
import 'dart:isolate';...loadData() async {//打开ReceivePort以接收传入的消息ReceivePort receiverPort = ReceivePort();//创建并生成与当前Isolate共享相同代码的Isolateawait Isolate.spawn(dataLoader,receiverPort.sendPort);//流的第一个元素SendPort sendPort = await receiverPort.first;//流的第一个元素被收到后监听会关闭,所以需要新打开一个ReceivePort以接收传入的消息ReceivePort response = ReceivePort();//通过此发送端口向其对应的‘ReceivePort’发送异步[消息],这个消息是指要发送的参数sendPort.send(["https://xxxx", response.sendPort]);//获取端口发来的数据List msg = await response.first;//更新UIsetState(() {widgets = msg;});}//Isolate的入口函数,该函数会在新的Isolate中调用, Isolate.spawn的message参数会作为调用它的唯一参数static dataLoader(SendPort sendPort) async {//打开ReceivePort以接收传入的消息ReceivePort port = ReceivePort();//通知其他的isolates,本isolate所监听的端口sendPort.send(port.sendPort);//获取其他端口发送的异步消息msgawait for (var msg in port) {//等价于List msg = await port.firstString data = msg[0];SendPort replyTo = msg[1];String dataURL = data;http.Response response = await http.get(dataURL);//其对应的“ReceivePort”发出解析出来的Json数据replyTo.send(json.decode(response.body));}}
dataLoader()是一个运行于自己独立线程上的Isolate。在Isolate里,你可以执行CPU密集型任务(如解析庞大的json,解析json也是很耗时的),或是计算密集型的数学操作,如加解密或信号处理等。
