Flutter-异步编程(二)

206 阅读4分钟

Flutter默认是单线程任务处理的,如果不开启新的线程,任务默认在主线程中处理。

 Dart的事件循环(event loop)

  1. 事件队列 (event queue)
    • 包含所有的外来事件:I/Omouse eventsdrawing eventstimersisolate之间的信息传递
  2. 微任务队列 (microtask queue)
    • 短时间内完成一个异步任务。优先级比event queue要高,只要队列中还有任务,就可以一直霸占着时间循环。microtask queue添加的任务主要是由 Dart内部产生。

因为 microtask queue 的优先级高于 event queue ,所以如果 microtask queue有太多的微任务, 那么就可能会霸占住当前的event loop。从而对event queue中的触摸、绘制等外部事件造成阻塞卡顿。

image.png

可以看到,在每一次事件循环中,Dart总是先去微任务队列microtask queue中查询是否有可执行的任务,如果没有,才会处理事件队列event queue的流程。

void test(){

  Future((){
    print('Future异步任务1');
  });
   
  sleep(Duration(seconds: 3));

  scheduleMicrotask((){
    print('微任务');
  });

  Future((){
    print('Future异步任务2');
  });
}

打印结果为:
flutter: 微任务
flutter: Future异步任务1
flutter: Future异步任务2

可以看到上述代码,scheduleMicrotask执行是在Future之前。

void test(){

  Future((){
    print('Future异步任务1');

    scheduleMicrotask((){
      print('微任务');
    });

  })
  .then((value) {
     print('执行Future.then 1方法');
  })
  .then((value) {
    print('执行Future.then 2方法');
  })
  .whenComplete(() {
    print('执行Future.whenComplete 方法');
  });

}

打印结果为:
flutter: Future异步任务1
flutter: 执行Future.then 1方法
flutter: 执行Future.then 2方法
flutter: 执行Future.whenComplete 方法
flutter: 微任务
flutter: Future异步任务3

如果在Future当中添加微任务队列,微任务队列是在整个Future执行完毕后才会执行微任务当中的代码。可以看到在同等级别下,scheduleMicrotask执行是在Future之前。

void test(){

  Future x1 =  Future((){
    print('Future1异步任务');

    scheduleMicrotask((){
      print('Future - x1 内部微任务');
    });

  })
  .then((value) {
     print('执行Future1.then 方法');
  });

  Future x2 = Future((){
    print('Future2异步任务');
  })
  .then((value) {
    print('执行Future2.then 方法');
  });

  x1.then((value) {
    print('结尾再次调用Future.then方法');
  });
}

打印结果为
flutter: Future1异步任务
flutter: 执行Future1.then 方法
flutter: 结尾再次调用Future.then方法
flutter: Future - x1 内部微任务
flutter: Future2异步任务
flutter: 执行Future2.then 方法

根据上述代码可以看到,如果Future已经执行完毕了,我们再来获取到这个Future的引用,然后再继续调用then()方法。对于这种情况,Dart会将后续加入的then()方法体放入microtask queue,尽快执行,所以结尾再次调用Future.then方法Future - x1 内部微任务之前,更是在Future2操作之前。

Future高级用法

Future.timeout

本来Future会在2s后完成,但是timeout声明的是1s后超时,所以1s后Future会抛出TimeoutException

void testFuture() {
     Future.delayed(Duration(seconds: 2), () {
      return 1;
    }).timeout(Duration(seconds:1)).then(print).catchError(print);
}
testFuture();
  
print("在testFuture()执行之后打印。");

打印结果为:
在testFuture()执行之后打印。
TimeoutException after 0:00:01.000000: Future not completed

 Future.foreach

根据某个集合对象,创建一系列的Future。并且会按顺序执行这些Future。例如,根据{1,2,3}创建3个延迟对应秒数的Future。执行结果为1秒后打印1,再过2秒打印2,再过3秒打印3,总时间为6秒:

void testFuture() {
  Future.forEach({1,2,3}, (int num){
    return Future.delayed(Duration(seconds: num),(){print("第$num秒执行");});
  });
}
testFuture();
  
print("在testFuture()执行之后打印。");

打印结果为:
在testFuture()执行之后打印。
第1秒执行
第2秒执行
第3秒执行

Future.wait

等待多个Future完成,并收集它们的结果。有两种情况:

  1. 所有Future都有正常结果返回。则Future的返回结果是所有指定Future的结果的集合:
void testFuture() async {
  var future1 = Future.delayed(Duration(seconds: 1), (){
    print('Future1执行完毕');
    return  'Future1执行完毕';
  });

  var future2 = Future.delayed(Duration(seconds: 2), (){
    print('Future2执行完毕');
    return  'Future2执行完毕';
  });

  var future3 = Future.delayed(Duration(seconds: 3),(){
    print('Future3执行完毕');
    return  'Future3执行完毕';
  });

  Future.wait({future1,future2,future3}).then((value){

    print('最终执行 value = $value');
  })
  .catchError((e){

  });
}

打印结果为:
flutter: Future1执行完毕
flutter: Future2执行完毕
flutter: Future3执行完毕
flutter: 最终执行 value = [Future1执行完毕, Future2执行完毕, Future3执行完毕]
  1. 其中一个或者几个Future发生错误,产生了error。则Future的返回结果是第一个发生错误的Future的值:
void testFuture() async {
  var future1 = Future.delayed(Duration(seconds: 1), (){
    print('Future1开始执行');
    return  'Future1执行完毕';
  });

  var future2 = Future.delayed(Duration(seconds: 2), (){
    print('Future2开始执行');
    throw 'Future2发生错误了';
    return  'Future2执行完毕';
  });

  var future3 = Future.delayed(Duration(seconds: 3),(){
    print('Future3开始执行');
    return  'Future3执行完毕';
  });

  Future.wait({future1,future2,future3}).then((value){
    print('最终执行 value = $value');
  })
  .catchError((e){
    print('捕获到了错误 ${e.toString()}');
  });
}

打印结果为:
flutter: Future1开始执行
flutter: Future2开始执行
flutter: Future3开始执行
flutter: 捕获到了错误 Future2发生错误了

Future.any

返回的是第一个执行完成的Future的结果,不会管这个结果是正确的还是error,如果数组中有多个then只会返回第一个执行的,剩下的Future还是会继续执行:

void testFuture() async {
  var future1 = Future.delayed(Duration(seconds: 1), (){
    print('Future1开始执行');
    return  'Future1执行完毕';
  });

  var future2 = Future.delayed(Duration(seconds: 2), (){
    print('Future2开始执行');
    return  'Future2执行完毕';
  });

  var future3 = Future.delayed(Duration(seconds: 3),(){
    print('Future3开始执行');
    return  'Future3执行完毕';
  });

  Future.any({future1,future2,future3}).then((value){
    print('最终执行 value = $value');
  })
  .catchError((e){
    print('捕获到了错误 ${e.toString()}');
  });
}

打印结果为:
flutter: Future1开始执行
flutter: 最终执行 value = Future1执行完毕
flutter: Future2开始执行
flutter: Future3开始执行

Future.sync

会同步执行其入参函数,然后调度到microtask queue来完成自己。也就是一个阻塞任务,会阻塞当前代码,sync的任务执行完了,代码才能走到下一行:

void main() {
  testFuture111112();

  print('end');
}
void testFuture111112()  {

  sleep(Duration(seconds: 3));

  Future((){
    print("Future event 1");
  });

  scheduleMicrotask((){
    print('微任务');
  });

  Future.sync(() {
    print("Future sync microtask event 2");
  });

  Future((){
    print("Future event 3");
  });

  Future.microtask((){
    print("microtask event");
  });

}
打印结果为:
flutter: Future sync microtask event 2
flutter: end
flutter: 微任务
flutter: microtask event
flutter: Future event 1
flutter: Future event 3