Flutter 异步机制 Future

Dart是一个单线程语言,当其遇到有延迟的运算(比如IO操作、延时执行)时,线程中按顺序执行的运算就会阻塞,可以使用异步操作使程序在等待一个耗时操作完成时继续处理其他工作。在Dart中,可以使用Future对象来表示异步操作的结果。

async和await

1.async用于标明函数是一个异步函数,其返回值类型是Future类型
2.await用来等待耗时操作的返回结果,这个操作会阻塞到后面的代码
3.后面的操作必须是异步才能用await
4.当前函数必须是异步函数

import 'package:flutter/material.dart';
String _data = '0';
void main() {
  getData();
  print('做其他的事情');

}
void getData() async{
  print('开始data=$_data');

  await Future((){
    //耗时操作
    for(int i = 0;i<1000000;i++){
      _data = '网络数据';
    }
  });
  print('结束data=$_data');
  print('干点其他的事情');
}

打印结果

Syncing files to device iPhone 8...
flutter: 开始data=0
flutter: 做其他的事情
flutter: 结束data=网络数据
flutter: 干点其他的事情

Future

首先Future是一个抽象类,Future表示一个指定类型的异步操作结果(不需要结果可以使用Future)当一个返回 future 对象的函数被调用时:

  1. 讲函数放入队列等待执行并返回一个未完成的Future对象

  2. 当函数操作执行完成,Future对象变为完成并携带一个值或一个错误
    上面两条分别对应两个状态:

  3. 运行状态(pending),表示任务还未完成,也没有返回值

  4. 完成状态(completed),表示任务已经结束(无论失败还是成功)

  • 使用future.then返回异步处理结果
import 'package:flutter/material.dart';
String _data = '0';
void main() {
  getData();
  print('做其他的事情');

}
void getData() async{
  print('开始data=$_data');
  Future future = Future((){
    //耗时操作
    for(int i = 0;i<1000000;i++){
      _data = '网络数据';
    }
    return _data;
  });
  future.then((value) => print(value));
  print('干点其他的事情');
}

打印结果

Syncing files to device iPhone 8...
flutter: 开始data=0
flutter: 干点其他的事情
flutter: 做其他的事情
flutter: 网络数据
  • 捕获异常
String _data = '0';
void main() {
  getData();
  print('做其他的事情');

}
void getData() async{
  print('开始data=$_data');
  Future((){
    //耗时操作
    for(int i = 0;i<1000000;i++){
    }
    throw Exception('网络异常');
  }).catchError((e){
    print('捕获到了:'+e.toString());
  }).then((value) {
      print('then来了');
      print(value);
  });
  print('干点其他的事情');
}

打印结果为

flutter: 开始data=0
flutter: 干点其他的事情
flutter: 做其他的事情
flutter: 捕获到了:Exception: 网络异常
flutter: then来了
flutter: null

除了这种方式也可以直接用then的方法来处理异常,点进去可以看到还有一个可选参数

  Future then(FutureOr onValue(T value), {Function? onError});

用这种方式实现如下:

void getData() async{
  print('开始data=$_data');
  Future future = Future((){
    //耗时操作
    for(int i = 0;i<1000000;i++){
    }
    throw Exception('网络异常');
  });
  future.then((value) {
      print('then来了');
      print(value);
  }).catchError((e){
    print('捕获到了:'+e.toString());
  });
  print('干点其他的事情');
}

打印结果为,这时候如果捕获到了异常不再执行then方法

flutter: 开始data=0
flutter: 干点其他的事情
flutter: 做其他的事情
flutter: 捕获到了:Exception: 网络异常
  • 完成状态
void getData() async{
  print('开始data=$_data');
  Future future = Future((){
    //耗时操作
    for(int i = 0;i<1000000;i++){
    }
    throw Exception('网络异常');
  });
  future.then((value) {
      print('then来了');
      print(value);
  }).catchError((e){
    print('捕获到了:'+e.toString());
  }).whenComplete((){
    print('完成了');
  });
  print('干点其他的事情');
}

打印结果为

flutter: 开始data=0
flutter: 干点其他的事情
flutter: 做其他的事情
flutter: 捕获到了:Exception: 网络异常
flutter: 完成了

flutter 异步任务如果不作处理的话是顺序执行的

void main() {
  testFuture();
  print('做其他事情');

}
void testFuture(){
 Future((){
   sleep(Duration(seconds: 1));
   return '任务1';
 }).then((value) => print('$value结束'));

 Future((){
   return '任务2';
 }).then((value) => print('$value结束'));
 Future((){
   return '任务3';
 }).then((value) => print('$value结束'));
 Future((){
   return '任务4';
 }).then((value) => print('$value结束'));
 print('任务添加完毕');
}

打印结果为

flutter: 任务添加完毕
flutter: 做其他事情
flutter: 任务1结束
flutter: 任务2结束
flutter: 任务3结束
flutter: 任务4结束

如果我们想控制任务间的依赖顺序,可以用then的方式来实现,通过以下方式可以看出then比future默认的队列优先级高

void testFuture(){
 Future((){
   sleep(Duration(seconds: 1));
   return '任务1';
 }).then((value){
   print('$value结束');
   return '任务4';
 }).then((value){
   print('$value结束');
 });

 Future((){
   return '任务2';
 }).then((value) => print('$value结束'));
 Future((){
   return '任务3';
 }).then((value) => print('$value结束'));

 print('任务添加完毕');
}

打印结果为

flutter: 任务添加完毕
flutter: 做其他事情
flutter: 任务1结束
flutter: 任务4结束
flutter: 任务2结束
flutter: 任务3结束
  • 多个异步处理,如果需要两个任务执行完后再执行,也可以采用下面的方式
void testFuture(){
  Future.wait([
    Future((){
      return '任务1';
    }),
    Future((){
      sleep(Duration(seconds: 1));
      return '任务2';
    }),
  ]).then((value) => print(value[0]+value[1]));

Dart的事件循环(event loop)

先看一个demo

void testFuture(){

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

打印结果为

flutter: 外部代码1
flutter: 外部代码2
flutter: 微任务A
flutter: A
flutter: A结束
flutter: B
flutter: B结束

Future是在事件队列中,从上面的结果可以看出微任务优先级是高于事件队列的。
在Dart中,实际上有两种队列:

事件队列(event queue),包含所有的外来事件:I/O、mouse events、drawing events、timers、isolate之间的信息传递。

微任务队列(microtask queue),表示一个短时间内就会完成的异步任务。它的优先级最高,高于event queue,只要队列中还有任务,就可以一直霸占着事件循环。microtask queue添加的任务主要是由 Dart内部产生。

在每一次事件循环中,Dart总是先去第一个microtask queue中查询是否有可执行的任务,如果没有,才会处理后续的event queue的流程。

2819433-efb1a2a14cd9b4df.png

看一个面试题

void testFuture4(){
  Future x = Future(()=>print('1'));
  Future(()=>print('2'));
  scheduleMicrotask(()=>print('3'));
  x.then((value) => print('4'));
  print('5');
}

打印结果为

flutter: 5
flutter: 3
flutter: 1
flutter: 4
flutter: 2

把这个demo调整一下

void testFuture4(){
  Future x1 = Future(()=>null);
  Future x = Future(()=>print('1'));
  Future(()=>print('2'));
  scheduleMicrotask(()=>print('3'));
  x.then((value) => print('4'));
  print('5');
  x1.then((value) => print('6'));
}
flutter: 5
flutter: 3
flutter: 6
flutter: 1
flutter: 4
flutter: 2

上面的估计大家都能答对,这时候我们再调整一下

void testFuture4(){
  Future x1 = Future(()=>null);
  x1.then((value){
    print('6');
    scheduleMicrotask(()=>print('7'));
  }).then((value) => print('8'));
  Future x = Future(()=>print('1'));
  Future(()=>print('2'));
  scheduleMicrotask(()=>print('3'));
  x.then((value) => print('4'));
  print('5');
  
}

打印结果

flutter: 5
flutter: 3
flutter: 6
flutter: 8
flutter: 7
flutter: 1
flutter: 4
flutter: 2

先打印8后打印7,这里then是立刻马上执行,所以比微任务7要快些,我们再多加一层看下

void testFuture4(){
  Future x1 = Future(()=>null);
  x1.then((value){
    print('6');
    scheduleMicrotask(()=>print('7'));
  }).then((value) => print('8'));
  Future x = Future(()=>print('1'));
  x.then((value){
    print('4');
    Future(()=>print('9'));
  }).then((value) => print('10'));
  Future(()=>print('2'));
  scheduleMicrotask(()=>print('3'));
  
  print('5');
  
}

打印结果为

flutter: 5
flutter: 3
flutter: 6
flutter: 8
flutter: 7
flutter: 1
flutter: 4
flutter: 10
flutter: 2
flutter: 9

最后再看一个demo

void isolateDemo() {
  loadData().then((value) => print('1结束'));
  loadData().then((value) => print('2结束'));
  loadData().then((value) => print('3结束'));
  loadData().then((value) => print('4结束'));
  loadData().then((value) => print('5结束'));
}

Future loadData() {
  return Future(() {
    compute(func1, 123);
  });
}
void func1(int count) {}

打印结果为

flutter: 1结束
flutter: 2结束
flutter: 3结束
flutter: 4结束
flutter: 5结束

这里我们修改一下,加一个return

void isolateDemo() {
  loadData().then((value) => print('1结束'));
  loadData().then((value) => print('2结束'));
  loadData().then((value) => print('3结束'));
  loadData().then((value) => print('4结束'));
  loadData().then((value) => print('5结束'));
}

Future loadData() {
  return Future(() {
    //如果你返回的是compute的Future,那么这个任务在子Isolate的事件队列中!
    return compute(func1, 123);
  });
}
void func1(int count) {}

打印结果为这个,结果变成了无序

flutter: 2结束
flutter: 1结束
flutter: 5结束
flutter: 4结束
flutter: 3结束

compute也会返回一个future,isolate是有自己的内存和单线程控制的运行实体,也有自己的事件循环队列,return之后拿到的futurn不再是主队列里面的,而是子isolate里的事件队列里,这里也就变成了异步返回,不再是有序返回

你可能感兴趣的:(Flutter 异步机制 Future)