一统天下 flutter - dart: 单线程异步编程(async/await/Future<T>/Stream<T>/StreamSubscription/Completer/Timer)

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

一统天下 flutter - dart: 单线程异步编程(async/await/Future/Stream/StreamSubscription/Completer/Timer)

示例如下:

lib\dart\async.dart

/*
 * dart 单线程异步编程(async/await/Future<T>/Stream<T>/StreamSubscription/Completer/Timer)
 *
 * 注:
 * 本例介绍的异步编程,只是在相同线程上的异步,并不是多线程,关于多线程请参见 isolate.dart
 */

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_demo/helper.dart';

class DartAsync extends StatelessWidget {
  const DartAsync({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    // 通过 async/await Future<T> 实现异步编程,等待与不等待,异常处理,超时处理
    sample1();
    // 演示 Stream<T> 的用法
    sample2();
    // 演示 StreamSubscription 的用法,以及如何取消 Future
    sample3();
    // 演示 Completer 的用法
    sample4();
    // 演示 Timer 的用法
    sample5();

    return const MyWidget(text: "dart_async");
  }

  // 如需在函数体内使用 await 则需要在函数体之前加上 async
  // 标记为 async 的函数会自动异步执行
  // async 函数有返回值则返回的类型是 Future<T>(可以省略 async)
  // async 函数没有返回值则返回的类型是 Future<void>(可以省略 async),也可以简写为 void(不可以省略 async)
  void sample1() async {

    // await 就是让它异步执行,然后等着它执行完
    log("sample1: 1, ${currentTimestamp()}");
    var a = await f1();
    log(a);
    log("sample1: 2, ${currentTimestamp()}");
    var b = await f2();
    log(b);


    // 异步编程的异常处理
    try {
      log("sample1: 3, ${currentTimestamp()}");
      var c = await f3();
    } catch (e) {
      log("$e");
    } finally {
      log("sample1: 4, ${currentTimestamp()}");
    }


    // then() 的用法
    log("sample1: 5, ${currentTimestamp()}");
    // 对于 async 函数来说,你也可以不 await 它,也就是说它会异步执行,但是你不用等它
    // then() - 当 Future 完成时会回调此方法(你不等他了怎么知道他完成了呢,就可以用这个)
    f4().then((value) => {
      log(value)
    });
    log("sample1: 6, ${currentTimestamp()}");


    // 使用 then() 时的异常处理(onError, catchError, whenComplete)
    f5().then((value) => log(value), onError:(e) {
      // 用于捕获 future() 过程中的异常
      log("onError: $e");
    }).catchError((e) {
      // 用于捕获 then() 过程中的异常
      // 如果没有在 then() 中定义 onError() 则这里也会捕获 future() 过程中的异常
      log("catchError: $e");
    }).whenComplete(() => {
      // 当 Future 完成后,无论是否发生异常都会走到这里,类似 finally
      log("whenComplete")
    });


    // 通过 Future 的 timeout() 实现异步的超时处理
    try {
      await f6().timeout(const Duration(seconds: 1));
    } catch (e) {
      // 超时后会捕获到 TimeoutException 类型的异常
      log("timeout: $e");
    }
    // 不用 try/catch 的话可以通过 onTimeout 处理超时后的回调
    var result = await f6().timeout(const Duration(seconds: 1), onTimeout: () {
      // 返回值的类型与你的 Future<T> 中 T 一样
      return "timeout";
    });
    log(result);
  }

  // Future<T> 的意思是函数需要异步执行,其可被 await
  // T 是函数的真实返回值
  Future<String> f1() async {
    // 等待 2 秒
    await Future.delayed(const Duration(seconds: 2));
    // 返回数据,假设返回值类型为 T 则在函数体之前加上 async 的话,会自动返回 Future<T> 类型的数据
    // 也就是说下面这句等同于 return Future.value("sample1: aaa");
    return "sample1: aaa";

    // 也可以使用 Future.then() 返回 Future<T> 类型的数据,下面这句等同于上面两句
    // return Future.delayed(const Duration(seconds: 2)).then((value) => "sample1: aaa");
  }

  Future<String> f2() {
    // 这个返回值本身就是 Future<T> 类型,所以可以不在函数体之前加 async
    return Future.delayed(const Duration(seconds: 2), () => 'sample1: bbb');
  }

  Future<String> f3() {
    // 抛出一个数据,用于演示异步编程的异常处理
    return Future.delayed(const Duration(seconds: 2), () => throw 'sample1: ccc');
  }

  Future<String> f4() {
    return Future.delayed(const Duration(seconds: 2), () => 'sample1: ddd');
  }

  Future<String> f5() {
    return Future.delayed(const Duration(seconds: 2), () => throw 'sample1: eee');
  }

  Future<String> f6() {
    return Future.delayed(const Duration(seconds: 2), () => 'sample1: fff');
  }



  void sample2() async {
    // 获取一个 Stream<T> 每迭代一次它会依次返回 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    var stream = myStream(10);
    log("sample2: ||||||||||");
    // 累加 Stream<T> 中迭代出的数据
    var sum = await myFuture(stream);
    log("sample2: $sum"); // sample2: 55
  }

  Future<int> myFuture(Stream<int> stream) async {
    var sum = 0;
    // 迭代 Stream<T>
    await for (final value in stream) {
      sum += value;
    }
    return sum;
  }

  // Stream<T> 是一个异步事件的序列,当你获取到 Stream<T> 的时候,它是不会执行的
  // 当你对它迭代的时候,如果有可迭代数据则每迭代一次就执行一次事件
  // 下面这个其实就是一个生成异步可迭代对象的生成器,关于生成器请参见 other.dart 中的关于生成器的说明
  Stream<int> myStream(int to) async* {
    for (int i = 1; i <= to; i++) {
      await Future.delayed(const Duration(seconds: 1));
      log("sample2: ---------- $i");
      yield i;
    }
  }



  void sample3() async {
    var stream = myStream2(10);
    // 通过 Stream 的 listen() 方法创建一个 StreamSubscription 对象用来管理 Stream
    // cancelOnError 如果是 false 则 Stream 异常后会走到 onDone
    // cancelOnError 如果是 true 则 Stream 异常后不会走到 onDone
    StreamSubscription<int> streamSubscription = stream.listen(null, cancelOnError: false);

    // 通过 StreamSubscription 可以控制对应的 Stream 的暂停和继续
    // streamSubscription.pause();
    // var isPaused = streamSubscription.isPaused;
    // streamSubscription.resume();

    // 取消 Stream(Stream 会被取消,且不会走到 onDone)
    // streamSubscription.cancel();

    // 收到 Stream 的数据时
    streamSubscription.onData((data) {
      log("sample3 onData: $data");
    });
    // Stream 发生异常时
    streamSubscription.onError((e) {
      log("sample3 onError: $e");
    });
    // Stream 的数据都收到时
    // 或者 Stream 发生异常了且 cancelOnError 为 false 时
    streamSubscription.onDone(() {
      log("sample3 onDone");
    });

    // Future 和 Stream 之间可以互相转换
    // 将 Stream 转换为 Future 后,要注意 onDone 和 onError 都不会被调用了,分别要用 Future 的 then() 和 catchError() 取代之
    // var myFuture = streamSubscription.asFuture();
    // 如果需要取消 Future 的话,你可以将其转换为 Stream,然后通过 StreamSubscription 取消
    // var myStream = myFuture.asStream();
  }

  Stream<int> myStream2(int to) async* {
    for (int i = 1; i <= to; i++) {
      await Future.delayed(const Duration(seconds: 1));
      if (i > 3) {
        throw Exception("error");
      }
      yield i;
    }
  }



  void sample4() async {
    try {
      // 对你自己的没有 async/await 的逻辑做异步编程
      var a = await myCompleter();                // Completer 通过 complete() 返回时,可在此处拿到返回值
      log("sample4: $a");                         // sample4: 888888
    } catch (e) {                                 // Completer 通过 completeError() 返回时,可在此处拿到异常值
      log("sample4 error: " + e.toString());      // sample4 error: -999
    }
  }

  // 当你自己的逻辑没有 async/await 时,但是你又想要异步编程,就可以使用 Completer 了
  Future<int> myCompleter() {
    // 实例化一个 Completer<T>,此处的 T 就是 Completer 的 future 属性返回的 Future<T> 中的 T
    Completer<int> c = Completer<int>();
    for (int i=0; i<10000000; i++) {
      if (i == 888888) {
        // 完成并返回指定类型的结果值(调用者通过 await 可以拿到此值)
        c.complete(i);

        // 完成并返回指定类型的异常值(调用者通过 catch 可以拿到此值)
        // c.completeError(-999);
        break;
      }
    }

    // 返回一个 Future<T> 对象,从而实现异步编程
    return c.future;
  }



  void sample5() {
    var timeout = const Duration(seconds: 3);
    log('currentTimestamp1:${currentTimestamp()}');
    // 指定的时间之后回调
    Timer(timeout, () {
      log('currentTimestamp1:${currentTimestamp()}');
    });

    var period = const Duration(seconds: 1);
    log('currentTimestamp2:${currentTimestamp()}');
    // 指定的间隔时间回调
    Timer.periodic(period, (timer) {
      log('currentTimestamp2:${currentTimestamp()}, ${timer.tick}');
      if (timer.tick >= 5) {  // 定时器的执行次数
        timer.cancel();       // 停止定时器
      }
    });
  }
}

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

posted @ 2023-03-22 09:33  webabcd  阅读(158)  评论(0编辑  收藏  举报