Flutter asynchronous 异步编程技巧
flutter async
视频
https://www.bilibili.com/video/BV1g1421t7Ag/
前言
深入探讨 Flutter 中 Future、Microtask 和并发处理的高效用法,为您的应用程序带来卓越的异步性能。包含 Future.wait、FutureBuilder 和 Microtask 任务分解等实用技巧。
参考
Dart asynchronous programming: Isolates and event loops
步骤
Future.wait
Future.wait()
是 Dart 中一个非常有用的异步操作方法,它允许我们并发执行多个异步任务,并在所有任务完成后统一处理结果。
Future.wait()
的主要特点如下:
- 并发执行:它允许我们并发执行多个异步操作,而不需要一个一个地等待它们完成。这对于需要汇总多个数据源的场景非常有用。
- 统一结果处理:当所有异步操作都完成后,
Future.wait()
会将它们的结果整合成一个 List,我们可以统一地处理这些结果。 - 错误处理:如果任何一个异步操作抛出异常,
Future.wait()
也会将这个异常抛出,我们可以在外层捕获并处理。 - 取消机制:如果我们在
Future.wait()
完成之前取消了它,那么其内部的所有异步操作也会被取消。 - 灵活使用:我们可以根据需求,自由地组合各种异步操作,如 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 具有以下特点:
- 优先级高于 Future: Microtasks 的执行优先级高于 Future,也就是说,即使有一个正在执行的 Future,如果有 Microtasks 需要执行,它们也会先于 Future 执行。
- 立即执行: 当 Microtasks 被添加到 event queue 中时,它们会立即执行,而不会等待当前事件循环结束。
- 同步执行: 与 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
从输出可以看出:
- 两个 Microtasks 先于 Future 执行,体现了 Microtasks 的高优先级。
- 两个 Microtasks 是立即执行的,并且是同步执行的,一个接一个地执行完毕。
Future
最后执行,因为它的优先级低于 Microtasks。
Microtasks 通常用于以下场景:
- 在 Widget 构建过程中更新状态:当 Widget 正在构建时,可以使用 Microtasks 来更新 Widget 的状态。
- 执行一些低开销的任务:如果一个任务执行开销很低,又需要立即执行,可以使用 Microtasks。
- 处理异步回调:当异步回调触发时,可以使用 Microtasks 来处理回调结果。
Flutter 中的 Microtasks 和 Isolate 是两个不同的概念,它们在处理并发和异步任务时起到不同的作用。
- Microtasks:
- Microtasks 是 Flutter 事件循环中的一种特殊任务类型。
- 它们会在当前事件循环周期结束前执行,优先级高于常规事件。
- Microtasks 通常用于执行一些简单、轻量级的异步任务,比如更新 UI 状态、触发回调函数等。
- Microtasks 是在主 Dart 隔离(Isolate)中执行的,因此它们可以直接访问 Flutter 应用程序的状态和 UI 元素。
- 使用
Future.microtask()
或SchedulerBinding.instance.addMicrotask()
可以将任务添加到 Microtasks 队列中。
- Isolate:
- Isolate 是 Dart 语言中的并发执行单元,类似于操作系统中的线程。
- 每个 Isolate 都有自己的内存空间,彼此之间不共享内存,通过消息传递的方式进行通信。
- Isolate 适用于执行 CPU 密集型或长时间运行的任务,例如图像处理、机器学习等。
- 使用
Isolate.spawn()
可以创建新的 Isolate,并在其中执行任务。 - Isolate 之间的通信使用
SendPort
和ReceivePort
机制进行,这样可以避免共享内存带来的线程安全问题。
总的来说,Microtasks 与 Isolate 的主要区别如下:
- 执行位置:Microtasks 在主 Dart Isolate 中执行,而 Isolate 是独立的并发执行单元。
- 任务类型:Microtasks 适用于轻量级、快速执行的任务,而 Isolate 适用于 CPU 密集型或长时间运行的任务。
- 通信机制:Microtasks 直接访问应用程序状态,而 Isolate 之间通过消息传递进行通信。
小结
Flutter 作为跨平台移动应用开发框架,其异步编程能力在应用性能优化中扮演着重要角色。本文详细介绍了 Flutter 中 Future、Microtask 和并发处理的高效使用方法,包括 Future.wait、FutureBuilder 和任务分解等实用技巧,旨在帮助开发者构建出更加响应迅速、流畅的 Flutter 应用程序。
感谢阅读本文
如果有什么建议,请在评论中让我知道。我很乐意改进。
猫哥 APP
flutter 学习路径
- Flutter 优秀插件推荐
- Flutter 基础篇1 - Dart 语言学习
- Flutter 基础篇2 - 快速上手
- Flutter 实战1 - Getx Woo 电商APP
- Flutter 实战2 - 上架指南 Apple Store、Google Play
- Flutter 基础篇3 - 仿微信朋友圈
- Flutter 实战3 - 腾讯即时通讯 第一篇
- Flutter 实战4 - 腾讯即时通讯 第二篇
© 猫哥 ducafecat.com
end