Dart中的异步与事件循环

前言

Dart做为Flutter的开发语言,了解Dart的机制是必可少的。本篇文章就介绍一下Dart的异步操做与事件循环机制。java

异步操做咱们都知道在开发过程当中,若是有耗时操做,咱们通常都会使用异步任务解决,以防主线程卡顿。markdown

事件循环是Dart中处理事件的一种机制。Flutter中就是经过事件循环来驱动程序的运行,这点与Android中的Handler有点相似。异步

Dart的事件循环机制

Dart语言是单线程模型的语言。这也就意味着Dart在同一时刻只能执行一个操做,其余操做在这个操做以后执行。那么Dart的其余操做如何执行呢?在Dart中经过Event Loop来驱动事件的执行。async

  • Dart程序启动时会建立两个队列,分别是MicroTak队列(微服务队列)和Event队列(事件队列);
  • 而后执行main()方法;
  • 最后启动事件循环;

上面的图片描述了Dart的事件循环机制。能够看到,Dart执行事件的流程是:函数

  1. 执行main();
  2. 执行MicroTask队列中事件;
  3. 执行事件队列中的事件;

能够看到,main()方法的优先级最高,执行结束后,才执行两个队列中事件。其中MicroTask队列的优先级又高于Event队列的优先级。微服务

MicroTask队列和Event队列

MicroTask 队列适用于很是简短且须要异步执行的内部动做或者想要在Event执行前作某些操做,由于在MicroTask执行完之后,还须要执行Event队列中事件。oop

在使用Dart时异步事件应该优先考虑使用Event队列。ui

Dart中的异步

Future

Future 是一个异步执行而且在将来的某一个时刻完成(或失败)的任务。每个Future都会执行一个事件而且将事件加入到Event队列中去。spa

factory Future(FutureOr<T> computation()) {
    _Future<T> result = new _Future<T>();
    Timer.run(() {
      try {
        result._complete(computation());
      } catch (e, s) {
        _completeWithErrorCallback(result, e, s);
      }
    });
    return result;
  }
复制代码

从上面Future的构造函数代码能够看到,经过Timer的run()方法将运算过程发送到事件队列中去,而后经过_complete()方法获取了提交给Future的运算结果,最终返回一个Future对象。pwa

void main(){
    print('Before the Future');
    Future((){
        print('Running the Future');
    }).then((_){
        print('Future is complete');
    });
    print('After the Future');
    Future<String>.microtask(() {
        return "microtask";
  	}).then((String value) {
    	print(value);
  	});
}
复制代码

以上代码的运行结果是:

Before the Future
After the Future
microtask
Running the Future
Future is complete
复制代码

能够看到,这里先执行的是main()方法中的打印信息,而后打印了microtask,最后才执行了Future。这里也能够证实Future是在事件队列中执行的。

async、await关键字

async与await关键字配合使用能够更加优雅的处理dart中的异步。对于有async修饰的函数来讲,它会同步执行函数中的代码,直到遇到第一个await关键字,而后将await修饰的代码提交到事件队列中处理,在await修饰的代码执行完毕后会当即执行剩下的代码,而剩下的代码将在微任务队列中执行。

void methodAsync() async {
  sleep(Duration(seconds: 1));
  Future<String>(() {
    return "future 1";
  }).then((String value) {
    print(value);
  });
  print("async start");
  await microTaskAndEvent(); //输出一个微任务打印 microtask 以及一个事件队列任务打印 futrue
  print("async end");
}

void main() {
    methodAsync();
  	print("Hello World");
}
复制代码

以上代码的输出结果是:

async start
Hello World
microtask
async end
future 1
future
复制代码

从打印结果能够看出,

  • 这里同步执行methodAsync()方法,即便在睡眠1s的状况下,也首先输出了async start;而后输出Hello World;
  • 接下来执行了一个Future1,而后执行await关键字后面的函数;
  • microTaskAndEvent()方法包括一个微任务和事件。这里能够看到打印了microtask接着打印了async end,这里能够证实async在await关键字以后的代码是放到微任务中执行的。
  • 最后打印了事件队列中的任务。

Isolate

Isolate从名称上理解是独立的意思。在dart中,Isolate有着本身的内存而且不存在经过共享内存的方式实现Isolate之间的通讯,同时Isolate是单线程的计算过程。

Isolate的特色与使用:

  • Isolate有着本身的内存而且不存在经过共享内存的方式实现Isolate之间的通讯;
  • 每一个Isolate都有本身的事件循环;
  • 在Isolate中是经过Port进行通讯的。Port分为两种一种是receive port用于接收消息。另一种是send port用于发送消息;
  • 使用Isolate时,能够经过spwan()方法启动一个Isolate

接下来经过一个例子展现Isolate的通讯以及建立过程。

main() async {
  var receivePort = new ReceivePort();
  /**  * 初始化另一个Isolate,  * 将main isolate的send port发送到child isolate中,  * 用于向main isolate发送信息  */
  await Isolate.spawn(echo, receivePort.sendPort);

  // child isolate的第一个信息做为child isolate的send port,因为向child isolate发送信息
  var sendPort = await receivePort.first;

  var msg = await sendReceive(sendPort, "hello");
  print('received $msg');
  msg = await sendReceive(sendPort, "close");
  print('received $msg');
}

// child isolate的入口
echo(SendPort sendPort) async {
  // 打开一个接收端口
  var port = new ReceivePort();
  //监听接收的信息
  port.listen((dynamic msg) {
    print("child receive $msg");
    var data = msg[0];
    SendPort replyTo = msg[1];
    replyTo.send(data);
    if (data == "close") port.close(); //关闭接收端口
  });

  // 向其余的isolate通知child isolate的发送端口.
  sendPort.send(port.sendPort);
}
//发送信息
Future sendReceive(SendPort port, msg) {
  ReceivePort response = new ReceivePort();
  port.send([msg, response.sendPort]);
  return response.first;
}
复制代码

总结

以上就是关于Dart的异步以及事件循环原理。理解这些内容是必要的,由于在不少的开发场景都会用到异步,同时须要很好的理解Dart的事件处理机制。

相关文章
相关标签/搜索