Flutter教程- Async(二) Future就像是盒子里的巧克力糖


发文时间:2022年04月13日 17:41:52     编辑:Aaron      标签:Flutter异步(Async) 图文详解系列 596


详细介绍Future的三种状态:未完成、正常完成和异常完成,最后也会介绍async await语法糖。

1、获取一个Future

image.png

//案例如下 假设写一个关于http的get请求
import 'package:http/http.dart' as http;
  void _incrementCounter() {
    http.get(Uri(host: 'www.baidu.com'));
  }
  
/// get方法返回的就是一个Future  (以下为get源码)
Future head(Uri url, {Map? headers}) =>
    _withClient((client) => client.head(url, headers: headers));

    在flutter中的Future就像是一个承诺,以后会返回一个(Response)对象,只是现在暂时没有还在获取中,但是以后会返回一个。

    Future就像是盒子里的巧克力糖,http.get请求就像返回一个Future,就像没有打开的盒子,当它有一天打开我们就能看看他里面有什么。

/// 打开之后我们可以用then看看盒子里装的是什么口味的糖
void _incrementCounter() {
    http.get(Uri(host: 'www.baidu.com')).then((value) => null);
  }

盒子打开也有可能会有错误,譬如网址错误

 void _incrementCounter2() {
    http.get(Uri(host: 'www.baidu.cn')).catchError((error) => null);
  }

Future一共有三种状态:

    Future刚建成时没有完成的状态

    正常完成时_.then得到一个值的状态

    异常完成时_.catchError得到一个错误信息的状态

程序中大部分的异步操作都是围绕这三种状态进行的。

除了大量的网络和IO请求会给我们一个Future外,我们也可以自己获取一个Future

  Future getFuture() {
  	return Future(() => 'alice');
    // 等待一秒钟返回值
    // return Future.delayed(Duration(seconds: 1), () => 'alice');
  }

  void _incrementCounter() {
    // 这里的操作都是异步的方式
    getFuture().then((value) => print(value));
    print('hi');
  }
输出结果:
hi
alice

二、Future运行方式

直接运行的Future

void main() {
  print('main 1');
  Future.sync(() => print('sync 1'));
  Future.value(getName());
  print('main2');
  runApp(MyApp());
}

String getName() {
  print('get name');
  return 'bob';
}
输出结果:
main 1
sync 1
get name
main 2

Microtask案例

void main() {
  scheduleMicrotask(() => print('microtask 1'));
  Future.microtask(() => print('microtask 2'));

  Future.value(123).then((value) => print('microtask 3'));

  print('main 1');
  Future.sync(() => print('sync 1'));
  Future.value(getName());
  print('main2');
  runApp(MyApp());
}

String getName() {
  print('get name');
  return 'bob';
}
输出结果:
main 1
sync 1
get name
main2
microtask 1
microtask 2
microtask 3

可以看到直接运行的Future执行完后,Event Loop循环事件开始执行Mirtotask里的事件 是按顺序来执行的

Event案例

String getName() {
  print('get name');
  return 'bob';
}

void _incrementCounter() async {

  // 等待一秒将打印事件加入Event
  Future.delayed(Duration(seconds: 1), () => print('event 3'));
  // 直接将打印事件加入Event
  Future(() => print('event 1'));
  // 等待0秒将打印事件加入Event
  Future.delayed(Duration.zero, () => print('event 2'));

  scheduleMicrotask(() => print('microtask 1'));
  Future.microtask(() => print('microtask 2'));
  //虽然Future.value属于直接运行但是因为有scheduleMicrotask的存在 所以得 microtask运行完后按顺序执行
  Future.value(123).then((value) => print('microtask 3'));

  print('main 1');
  Future.sync(() => print('sync 1'));
  Future.value(getName()).then((value) => print(value));
  print('main2');
  runApp(M
输出结果:
flutter: main 1
flutter: sync 1
flutter: get name
flutter: main2
flutter: microtask 1
flutter: microtask 2
flutter: microtask 3
flutter: bob
flutter: event 1
flutter: event 2
flutter: event 3

可以看到直接运行的Future执行完后,Event Loop循环事件开始执行Mirtotask里的事件。
只有当Microtask里的事件执行完,才会去执行Event里的事件

image.png

难点证明

 1.在已经完成的Future上会执行microtask

Future(() => print('event 1'));

scheduleMicrotask(() => print('microtask 1'));

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

Future.value(123).then((value) => print('microtask 3'));

输出结果:
microtask 1
microtask 2
microtask 3
event 1

    可以看到microtask 3 是在event 1前执行的,而event 1是第一个加入Event中的, microtask 3 先于event 1打印其事件必然添加到Micrtotask中的。

    Future.value(123)是立即执行的,这也就证明了证明了立即执行的Future,它的.then会往Microtask添加一个事件的。

 2.一个普通的等待的Future,等待它完成的瞬间.then 会直接执行,不会多添加一次事件

Future.delayed(Duration(seconds: 1), () => print('delayed')).then((value) {
    scheduleMicrotask(() => print('micro'));
    print('then');
  }).then((value) {
    print('then 2');
  });
  
输出结果:
delayed
then
then 2
micro

    可以看到,等待1秒的Future,打印了delayed,往Microtask添加打印micro事件,再打印then,Future.then方法返回值也是Future,继续打印then2。

    micro是第一个加入Microtask中的,它的优先级是高于Event的,所以then then2 想要先于micro打印,不可能继续往Microtask或Event中添加事件。

    这也就证明了一个普通的等待的Future,等待它完成的瞬间.then 会直接执行,不会多添加一次事件

三、获取一个错误的Future

前面我们已经知道Future有,未完成,完成,错误三种状态,这里我们获取错误完成状态

void _incrementCounter() {
	getFuture().then((value) => print(value));
}
  
Future getFuture() {
    return Future.error(Exception('something went wrong'));
}

输出结果:
Unhandled Exception: Exception: something went wrong
未处理的异常

void _incrementCounter() {
    getFuture().then((value) => print(value)).catchError((err) => print(err));
  }

  Future getFuture() {
    return Future.error(Exception('something went wrong'));
  }

输出结果:
Exception: something went wrong
没有说未处理过得异常

异常Future跑出异常并不会走.then而应该用.catchError捕获异常

void _incrementCounter() {
    getFuture()
        .then((value) => print(value))
        .catchError((err) => print(err))
        .whenComplete(() => print('complete'));
  }

Future getFuture() {
  return Future.error(Exception('something went wrong'));
}

输出结果:
Exception: something went wrong
complete

Future运行完,不管是正常执行完,还是错误,都会执行.whenComplete

  void _incrementCounter() {
    getFuture()
        .then((value) {
          print(value);
          return value * 2;
        })
        .then((value) => print(value))
        .catchError((err) => print(err))
        .whenComplete(() => print('complete'));
  }

  Future getFuture() {
    return Future.value(100);
  }
  
输出结果:
100
200
complete

使用async修饰方法为异步方法,必须返回Future;await负责等待Future执行完

  void _incrementCounter() async {
    int id = await getFuture();
    print(id);
    id *= 2;
    print(id);
  }

  Future getFuture() async {
    return 100;
  }
  
输出结果:
100
200
  void _incrementCounter() {
    Future id = getFuture();
    print(id);
  }

  Future getFuture() async {
    return 100;
  }
  
  输出结果:
Instance of ‘Future’
没有使用await直接获取的就是一个Future

使用async/await 异常捕获变得更加简洁,好处理

  void _incrementCounter() async {
    try {
      int id = await getFuture();
      print(id);
    } catch (err) {
      print('err:$err');
    }
  }

  Future getFuture() async {
    throw 'oops';
  }
  
输出结果:
err:oops

多个then案例

void _incrementCounter() async {
  //可多个then操作 一步步操作 如读取数据库的操作,先获取用户id 然后通过用户id获取对应的信息等
  Future.value(10)
      .then((value) {
        print('当前的值为 ${value}');
        //通过return返回给下一级值
        return value * 2;
      })
      .then((value) {
        print('接收上一级来的value ${value}');
      })
      .catchError((error) => print('发生错误咯 ${error}'))
      .whenComplete(() => print('运行完成了'));

  runApp(MyApp());
}

输出
flutter: 当前的值为 10
flutter: 接收上一级来的value 20
flutter: 运行完成了


 

若无特殊说明,此文章为博主原创。
写稿不易,如需转载,请注明出处: https://www.aaroner.cn/art/52.html




SITE MAP

  FOLLOW US