Flutter asynchronous 异步编程技巧

flutter async

视频

https://youtu.be/Hn_PxYzsG8U

https://www.bilibili.com/video/BV1g1421t7Ag/

前言

原文 Flutter 异步编程技巧与最佳实践

深入探讨 Flutter 中 Future、Microtask 和并发处理的高效用法,为您的应用程序带来卓越的异步性能。包含 Future.wait、FutureBuilder 和 Microtask 任务分解等实用技巧。

参考

async 官方说明

AsyncSnapshot 类说明

Dart asynchronous programming: Isolates and event loops

步骤

Future.wait

Future.wait() 是 Dart 中一个非常有用的异步操作方法,它允许我们并发执行多个异步任务,并在所有任务完成后统一处理结果。

Future.wait() 的主要特点如下:

  1. 并发执行:它允许我们并发执行多个异步操作,而不需要一个一个地等待它们完成。这对于需要汇总多个数据源的场景非常有用。
  2. 统一结果处理:当所有异步操作都完成后,Future.wait() 会将它们的结果整合成一个 List,我们可以统一地处理这些结果。
  3. 错误处理:如果任何一个异步操作抛出异常,Future.wait() 也会将这个异常抛出,我们可以在外层捕获并处理。
  4. 取消机制:如果我们在 Future.wait() 完成之前取消了它,那么其内部的所有异步操作也会被取消。
  5. 灵活使用:我们可以根据需求,自由地组合各种异步操作,如 API 请求、文件 I/O 等,并用 Future.wait() 一起执行。

假设你有多个计算密集型的异步调用需要执行。每个调用完成都需要几秒钟的时间,如下代码中的延迟所示。

Future<void> asyncOperation1() async {
    await Future.delayed(
        Duration(seconds: 2), () => print('Async Operation 1'));
  }

  Future<void> asyncOperation2() async {
    await Future.delayed(
        Duration(seconds: 3), () => print('Async Operation 2'));
  }

  Future<void> asyncOperation3() async {
    await Future.delayed(
        Duration(seconds: 4), () => print('Async Operation 3'));
  }

如果你使用 await 方式执行它们,完成时间将是每个操作执行时间的总和,9 秒钟。

void awaitApproach() async {
    print('Start: ${DateTime.now()}');
    await asyncOperation1();
    await asyncOperation2();
    await asyncOperation3();
    print('End: ${DateTime.now()}');
 }

/*
Start: 2024–02–18 12:08:30.205252
Async Operation 1 
Async Operation 2
Async Operation 3
End: 2024–02–18 12:08:39.221854
*/

使用 Future.wait 将会看到是并行执行的 , 5 秒钟。

void futureWaitApproach() async {
    print('Start: ${DateTime.now()}');
    await Future.wait([asyncOperation1(), asyncOperation2(), asyncOperation3()]);
    print('End: ${DateTime.now()}');
}

/*
Start: 2024-02-18 12:16:20.796960
Async Operation 1
Async Operation 2
Async Operation 3
End: 2024-02-18 12:16:24.804660
*/

Future.wait并行

Future.wait 并发执行

Future.wait 总是返回一个 List。

如果是不同的返回值,返回类型 List<Object> , 你可以通过枚举或者下标方式访问 result[0]

  var futures = [
    Future.value(42),
    Future.value('hello'),
  ];

  var result = await Future.wait(futures);
  print(result); // [42, hello]
  print(result[0].runtimeType); // int
  print(result[1].runtimeType); // String
  print(result.runtimeType); // List<Object> 

FutureBuilder

FutureBuilder 可以帮助您减少样板代码和复杂性,适用于需要根据异步交互构建 widget 小部件的场景。它提供了一种直接的方法来访问 Future 的 snapshot 快照状态,并相应地处理 UI。

AsyncSnapshot 参考

https://api.flutter.dev/flutter/widgets/AsyncSnapshot-class.html

举例:

FutureBuilder(
  future: _fetchData(), // 异步操作, 比如通过 api 拉取数据
  builder: (context, snapshot) {
    // 根据异步操作的状态更新UI
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator(); // 正在加载
    } else if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}'); // 发生错误
    } else {
      final data = snapshot.data;
      return ListView.builder(
        itemCount: data.length,
        itemBuilder: (context, index) {
          return Text('Item ${index}: $data[index]');
        },
      ); // 加载成功
    }
  },
)
FutureBuilder 的使用场景是小 widget ,他需要 StatefulWidget 的支持,所以性能一般,如果你是大范围使用,还是要考虑专业的状态管理组件 provider getx bloc 这种。

microtask

Microtask queue and event queue flow diagram in Flutter.

Microtasks 是 Dart 语言中的一种特殊任务类型,它们会在当前事件循环的末尾执行。与普通的异步任务(Future)不同,Microtasks 具有以下特点:

  1. 优先级高于 Future: Microtasks 的执行优先级高于 Future,也就是说,即使有一个正在执行的 Future,如果有 Microtasks 需要执行,它们也会先于 Future 执行。
  2. 立即执行: 当 Microtasks 被添加到 event queue 中时,它们会立即执行,而不会等待当前事件循环结束。
  3. 同步执行: 与 Future 不同,Microtasks 是同步执行的,它们会在当前事件循环的末尾,一个接一个地执行完毕。

例子

void main() {
  print('Start');

  // 添加一个 Microtask
  scheduleMicrotask(() {
    print('Microtask 1');
  });

  // 添加一个 Future
  Future(() {
    print('Future');
  });

  // 添加另一个 Microtask
  scheduleMicrotask(() {
    print('Microtask 2');
  });

  print('End');
}

输出

Start
End
Microtask 1
Microtask 2
Future

从输出可以看出:

  1. 两个 Microtasks 先于 Future 执行,体现了 Microtasks 的高优先级。
  2. 两个 Microtasks 是立即执行的,并且是同步执行的,一个接一个地执行完毕。
  3. Future 最后执行,因为它的优先级低于 Microtasks。

Microtasks 通常用于以下场景:

  1. 在 Widget 构建过程中更新状态:当 Widget 正在构建时,可以使用 Microtasks 来更新 Widget 的状态。
  2. 执行一些低开销的任务:如果一个任务执行开销很低,又需要立即执行,可以使用 Microtasks。
  3. 处理异步回调:当异步回调触发时,可以使用 Microtasks 来处理回调结果。

Flutter 中的 Microtasks 和 Isolate 是两个不同的概念,它们在处理并发和异步任务时起到不同的作用。

  1. Microtasks:

    • Microtasks 是 Flutter 事件循环中的一种特殊任务类型。
    • 它们会在当前事件循环周期结束前执行,优先级高于常规事件。
    • Microtasks 通常用于执行一些简单、轻量级的异步任务,比如更新 UI 状态、触发回调函数等。
    • Microtasks 是在主 Dart 隔离(Isolate)中执行的,因此它们可以直接访问 Flutter 应用程序的状态和 UI 元素。
    • 使用 Future.microtask()SchedulerBinding.instance.addMicrotask() 可以将任务添加到 Microtasks 队列中。
  2. Isolate:

    • Isolate 是 Dart 语言中的并发执行单元,类似于操作系统中的线程。
    • 每个 Isolate 都有自己的内存空间,彼此之间不共享内存,通过消息传递的方式进行通信。
    • Isolate 适用于执行 CPU 密集型或长时间运行的任务,例如图像处理、机器学习等。
    • 使用 Isolate.spawn() 可以创建新的 Isolate,并在其中执行任务。
    • Isolate 之间的通信使用 SendPortReceivePort 机制进行,这样可以避免共享内存带来的线程安全问题。

总的来说,Microtasks 与 Isolate 的主要区别如下:

  1. 执行位置:Microtasks 在主 Dart Isolate 中执行,而 Isolate 是独立的并发执行单元。
  2. 任务类型:Microtasks 适用于轻量级、快速执行的任务,而 Isolate 适用于 CPU 密集型或长时间运行的任务。
  3. 通信机制:Microtasks 直接访问应用程序状态,而 Isolate 之间通过消息传递进行通信。

小结

Flutter 作为跨平台移动应用开发框架,其异步编程能力在应用性能优化中扮演着重要角色。本文详细介绍了 Flutter 中 Future、Microtask 和并发处理的高效使用方法,包括 Future.wait、FutureBuilder 和任务分解等实用技巧,旨在帮助开发者构建出更加响应迅速、流畅的 Flutter 应用程序。

感谢阅读本文

如果有什么建议,请在评论中让我知道。我很乐意改进。


猫哥 APP

flutter 学习路径


© 猫哥
ducafecat.com

end


独立开发者_猫哥
669 声望128 粉丝