Flutter(二十四)-Dart事件循环机制

「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战

我们在前面已经大致了解了FlutterFuture的运行机制,那么除了FutureFlutter中是否还有其他任务机制呢?

我们先来看一段代码:

void testFuture() {
  print('外部代码1');
  Future(() => print('任务A')).then((value) => print('A任务结束'));
  Future(() => print('任务B')).then((value) => print('B任务结束'));
  print('外部代码2');
}
复制代码

按照我们在之前文章中介绍的Future的用法及执行流程,我们很容易就能猜到运行结果:

image.png

那么,如果在代码运行过程中,突然有紧急任务需要先执行,那么有没有办法处理呢?这就要使用到微任务来做处理了;

scheduleMicrotask

scheduleMicrotask又称为微任务,我们将代码修改一下,添加一个微任务看一下代码的执行流程发生了什么变化?我们将代码修改如下:

void testFuture() {
  print('外部代码1');
  Future(() => print('任务A')).then((value) => print('A任务结束'));
  Future(() => print('任务B')).then((value) => print('B任务结束'));
  scheduleMicrotask(() {
    print('微任务A');
  });
  sleep(const Duration(seconds: 1));
  print('外部代码2');
}
复制代码

在代码的执行流程中添加了scheduleMicrotask微任务,那么代码的执行结果是什么呢?

iShot2021-11-14 17.40.49.gif

根据打印信息,我们发现我们在Future后边添加的scheduleMicrotask微任务竟然优先执行了;scheduleMicrotask拥有较高的优先级,进而我们也能够确定在这段代码执行的过程中是有两个队列存在的,否则微任务不发优先执行;

Dart中的队列

Dart中是有两种对类存在的:

  • event queue事件队列:这种队列包含所有的外来事件,如I/Omouse eventsdrawing eventstimersIsolate等之间的信息传递;
  • microtask queue微任务队列:这种队列表示一个短时间内就会完成的异步任务。它的优先级最高,只要此队列中还有任务,就可以一直霸占着事件循环。microtask queue添加的任务主要是由Dart内部产生的。

需要注意的是,正因为microtask queue队列的优先级高于event queue队列,所以如果在microtask queue中的微任务过多,那么就有可能一直霸占当前的事件循环(event loop)。从而对event queue中的触摸、绘制等事件产生影响,导致这些时间产生阻塞卡顿;

在每一次的事件循环中,Dart总是会优先在microtask queue队列中查询是否还有可执行的任务,如果该队列中没有需要处理的任务,那么才会处理event queue队列中的任务及其流程;

在异步任务中,我们使用的最多的还是优先级较低的event queueDart中为event queue的任务做了一层封装,也就是我们之前使用过的Future

DartFuture异步任务的执行流程:

  • 声明一个Future时,Dart会将异步任务的函数执行体放入event queue中,然后立即返回,后续的代码继续进行同步执行;
  • 当同步执行的代码执行完毕后,event queue会按照加入的顺序也就是声明顺序,依次取出事件,最后同步执行Future的函数体及后续操作;

事件示例

我们来定义一串任务,代码如下:

void testFuture() {
  Future f1 = Future(() => null);
  f1.then((value) {
   print('6');
  }).then((value) => print('7'));

  Future f2 = Future(() => print('1'));
  f2.then((value){
    print('4');
  });

  Future(() => print('2'));

  scheduleMicrotask(() {
    print('3');
  });

  print('5');
}
复制代码

按照我们对Future任务执行顺序的理解,以及scheduleMicrotask具有较高优先级的执行权,那么其打印顺序应该是:

5、3、6、7、1、4、2

我们查看打印结果:

image.png

确实和我们预料的一样,那么我们将代码作如下修改呢?

void testFuture() {
  Future f1 = Future(() => null);
  f1.then((value) {
   print('6');
   scheduleMicrotask(() {
     print('8');
   });
  }).then((value) => print('7'));

  Future f2 = Future(() => print('1'));
  f2.then((value){
    print('4');
  });

  Future(() => print('2'));

  scheduleMicrotask(() {
    print('3');
  });

  print('5');
}
复制代码

我们在f1的任务中,添加了一个微任务,那么我们来看一下此时的打印结果:

image.png

看到这个结果,我们不免会产生疑问?scheduleMicrotask是微任务,那么他的优先级应该是最高的,那么8为什么会在7的后边打印呢?

此处需要注意的是,then内部的代码,我们可以看做这部分代码被扔在了微任务队列中,而scheduleMicrotask虽然也是微任务,但是此时它仅仅是扔在了微任务队列中,当前的微任务队列中还有打印7的任务,所以最终是78的前边打印;

猜你喜欢

转载自juejin.im/post/7033204529105469447
今日推荐