淘先锋技术网

首页 1 2 3 4 5 6 7

    在Flutter开发中,一般使用Future、Stream、async/wait使用异步操作。 Future类用于异步任务、Stream类主要用文件IO, 而async/wait是关键字。 

  官方介绍:Dart消息循环 https://webdev.dartlang.org/articles/performance/event-loop

       打开future.dart可以看到Future抽象类依赖Timer抽象类, 而Timer抽象类又依赖Zone抽象类(zone.dart)。 Future是对Timer类的封装, 而Timer类又是对Zone类的封装。 注意这3个类的关系是依赖,而不是继承。在Flutter开发中,也可以直接使用Timer或者Zone实现异步任务。

  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;
  }

  值得注意的是用户输入、Timer、点击事件运行在一个线程中( 即Main isolate)。 Dart消息队列的特点有2个队列, 即event queue和microtask queue。

event queue:包括IO、鼠标事件、绘制事件、定时器、dart isolate之间的消息等等;Futter添加的异步任务都就是向event queue里添加。

microtask:可以理解为拦截器,优先级比event queue要高。 即microtask里的任务必须执行完后,才能执行event queue。

为了加深对Futter的理解, 先看一段代码:

void main() {
  print("this is dart entrance");

  Future future1 = new Future(() => null);
  future1.then((_) {
    print("future1 then");
  }).catchError((e) {
    print("future1 catchError");
  }).whenComplete(() {
    print("future1 whenComplete");
  });

  Future future2 = new Future((){
    print("future2 init");
  });

  future2.then((_) {
    print("future2 then");
    future1.then((_){
      print("future1 excute by future2");
    });
  }).catchError((e) {
    print("future2 catchError");
  }).whenComplete(() {
    print("future2 whenComplete");
  });

  future1.then((_) {
    print("future1 reexecute");
  });

  Future future3 = new Future((){
    print("future3 init");
  });
  print("this is dart end");

}

运行结果:

this is dart entrance
this is dart end
future1 then
future1 whenComplete
future1 reexecute
future2 init
future2 then
future2 whenComplete
future1 excute by future2
future3 init

原理解释:

1、main方法执行完成后,才能执行event queue里的定时器。 所以最先打印前2句。

2、为什么“future1 reexecute”先于future2? 请注意Future的构造函数, 在实例化Future对象时已经向event queue里新增了一个Timer,执行then只是设置回调函数。 总结一下:一个Future可以注册多个then、delay等回调; Future的执行时序是按照Future实例化的先后顺序执行的。

3、为什么"future1 execute by future2"执行在“future3 init”之前? 请看then函数的注释, 在futurer2的then执行时, future1已经结束了,即event loop正在处理future2。再次调用future1.then会将timer添加到microtask, 这时microtask优先于event queue里的future3, 所以先打印了"future1 execute by future2"。

   * When this future completes with a value,
   * the [onValue] callback will be called with that value.
   * If this future is already completed, the callback will not be called
   * immediately, but will be scheduled in a later microtask.

4、then是Future注册的回调函数, 如果Future已经完成(即event loop处理它后面的event),那么会在microtask里调度执行。

   catchError是then函数里抛出异常后被捕获。

   whenComplete是最后执行的。

  为了加深理解,Future的then/catchError/whenComplete执行时序同Java的try/catch/finally。 catchError不一定执行,但whenComplete肯定是最后执行。

 

在业务开发中可能碰到这个场景, 多个网络接口api都返回后才能刷新UI, 即等待若干个异步任务全部结束后触发某个行为, 这时可以使用Future.wait函数。

   * Waits for multiple futures to complete and collects their results.
   *
   * Returns a future which will complete once all the provided futures
   * have completed, either with their results, or with an error if any
   * of the provided futures fail.
Future future3 = new Future((){
    print("future3 init");
    return "future3";
  });
  print("this is dart end");

  Future.wait([
    Future.delayed(new Duration(seconds: 1), () {
      print("do something1");
      return "hello world";
    }),
    future3,
    Future.delayed(new Duration(seconds: 1), () {
      print("do something2");
      return "hello world2222";
    })
  ]).then((results) {
    print(results);
  }).catchError((e) {
    print(e);
  });

在wait里可以执行多个Future, 待全部执行完成后执行then。

do something1
do something2
[hello world, future3, hello world2222]