18.异步编程之Future

代码执行顺序

下面一段代码的执行顺序是很明显的

int number = 1;

void main() {
  print('${DateTime.now()} start: $number');

  doSomeThing();

  print('${DateTime.now()} end: $number');
}

doSomeThing() {
  for(int i = 0; i < 1000000000; i++) {
    number += 1;
  }
  print('${DateTime.now()}  $number');
}

顺序输出没有什么问题

flutter: 2021-11-26 19:53:59.727819 start: 1
flutter: 2021-11-26 19:54:02.463404  1000000001
flutter: 2021-11-26 19:54:02.463815 end: 1000000001

async

加上 async 呢?是不是就变成异步的了?

int number = 1;

void main() {
  print('${DateTime.now()} start: $number');

  doSomeThing();

  print('${DateTime.now()} end: $number');
}

doSomeThing() async {
  for(int i = 0; i < 1000000000; i++) {
    number += 1;
  }
  print('${DateTime.now()}  $number');
}

并没有什么变化,依然按顺序同步执行。

flutter: 2021-11-26 19:57:19.945126 start: 1
flutter: 2021-11-26 19:57:22.676219  1000000001
flutter: 2021-11-26 19:57:22.678135 end: 1000000001

Future

在上文16.第三方库导入与网络数据异步请求与展示中我们的有用到 Future 进行异步网络请求。这里我们模拟网络请求,将耗时操作进行包装:

int number = 1;

void main() {
  print('${DateTime.now()} start: $number');

  doSomeThing();

  print('${DateTime.now()} end: $number');
}

doSomeThing() {
  Future( () {
    for(int i = 0; i < 1000000000; i++) {
      number += 1;
    }
    print('${DateTime.now()}  $number');
  });
}

通过打印我们发现这里的确是异步执行的:

flutter: 2021-11-26 20:01:22.301321 start: 1
flutter: 2021-11-26 20:01:22.306180 end: 1
flutter: 2021-11-26 20:01:25.041822  1000000001

Future是什么

通过查看源码我们能够发现。它是一个工厂构造函数。

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

async - await

思考一下,下面代码的执行顺序会是什么样呢?

nt number = 1;

void main() {
  print('${DateTime.now()} start: $number');

  doSomeThing();

  print('${DateTime.now()} end: $number');
}

doSomeThing() async {
  await Future( () {
    for(int i = 0; i < 1000000000; i++) {
      number += 1;
    }
    print('${DateTime.now()}  $number');
  });
  print('doSomeThing结束');
}

这里进行一下简单的分析:

  • doSomeThing

    • Future 是异步执行的

    • Future 加了 await,那么在当前作用域中,后面的代码就会被阻塞。

      • print('doSomeThing结束'); 这段代码会等待 Future 内的任务完成才执行。

  • main 函数内

    • 三行代码执行是按顺序执行的,不会受 doSomeThing 内部的 await 的影响

  • 按照预期输出应为:

    • start

    • end

    • print('${DateTime.now()} $number');

    • doSomeThing结束

执行验证✅

flutter: 2021-11-26 20:09:46.105049 start: 1
flutter: 2021-11-26 20:09:46.114976 end: 1
flutter: 2021-11-26 20:09:48.872681  1000000001
flutter: doSomeThing结束

async 和 await 是成对出现的。你也可以试试只写 await,看看是什么效果。

then 与任务的返回值

Future 有所了解的话,知道通过 then 我们可以在任务完成的时候进行一些操作。下面对代码嫂做修改:

int number = 1;

void main() {
  print('${DateTime.now()} start: $number');

  doSomeThing();

  print('${DateTime.now()} end: $number');
}

doSomeThing() async {
  await Future( () {
    for(int i = 0; i < 1000000000; i++) {
      number += 1;
    }
    print('${DateTime.now()}  $number');
  }).then( (value) {
    print('then: ${DateTime.now()}  $value');
  });
  print('doSomeThing结束');
}

输出:

flutter: 2021-11-26 20:20:39.641708 start: 1
flutter: 2021-11-26 20:20:39.649521 end: 1
flutter: 2021-11-26 20:20:42.388725  1000000001
flutter: then: 2021-11-26 20:20:42.390922  null
flutter: doSomeThing结束

这里 then 回调里的 value 是空的,该怎样为 value 赋值呢?很简单,直接在 Future 的任务中 return 就可以了

这里再次修改代码:

int number = 1;

void main() {
  print('${DateTime.now()} start: $number');

  doSomeThing();

  print('${DateTime.now()} end: $number');
}

doSomeThing() async {
  await Future( () {
    for(int i = 0; i < 1000000000; i++) {
      number += 1;
    }
    return number;
  }).then( (value) {
    print('then: ${DateTime.now()}  $value');
  });
  print('doSomeThing结束');
}

输出验证✅

flutter: 2021-11-26 20:23:45.843172 start: 1
flutter: 2021-11-26 20:23:45.850300 end: 1
flutter: then: 2021-11-26 20:23:48.584267  1000000001
flutter: doSomeThing结束

符合预期。

Last updated