dart:async 提供 Dart 异步编程核心能力:Future、Stream。
小提示:
- 使用
Future / Stream不一定需要手动 import dart:async,dart:core 已经导出;- 如果要使用
StreamController、StreamSubscription、ParallelWaitError等类型,需要显式导入:
import 'dart:async';Code language: JavaScript (javascript)
两大核心概念:
- Future:代表单次异步结果(未来某个时刻只会产生一个值/一次错误)
- Stream:代表连续一串异步数据(持续产生多个值、类似事件流)
Future
1. async / await(优先推荐,可读性高于 .then() 链式调用)
- 标记
async的函数返回 Future; await等待 Future 完成,阻塞当前代码直到结果返回;- 使用
try-catch捕获异步异常。
// async 函数返回 Future
Future<String> findEntryPoint() async => "main.dart";
Future<int> runExecutable(String entry, List args) async => 0;
Future<void> flushThenExit(int code) async {}
// await 写法(推荐)
Future<void> runUsingAsyncAwait() async {
try {
var entryPoint = await findEntryPoint();
var exitCode = await runExecutable(entryPoint, []);
await flushThenExit(exitCode);
} catch (e) {
// 统一捕获异常
print("出错:$e");
}
}Code language: JavaScript (javascript)
2. .then() / .catchError() 传统链式写法
.then():Future成功完成后执行回调;返回新Future,可以持续链式调用.catchError():捕获异常;必须链在 then 返回值后面,否则无法捕获 then 内部异常
void runUsingFuture() {
findEntryPoint()
.then((entryPoint) {
return runExecutable(entryPoint, []);
})
.then(flushThenExit)
.catchError((e) {
print("异常:$e");
});
}Code language: JavaScript (javascript)
3. 等待多个并发 Future
① Future.wait()
等待所有任务执行完毕;任意一个Future报错,整体直接失败
Future<void> task1() async {}
Future<void> task2() async {}
Future<void> task3() async {}
void testWait() async {
await Future.wait([
task1(),
task2(),
task3(),
]);
print("全部任务执行完成");
}Code language: JavaScript (javascript)
② List.wait / Record.wait(新特性,精细处理并发错误)
抛出 ParallelWaitError,可以区分哪些成功、哪些失败,互不打断。
Future<int> delete() async => 1;
Future<String> copy() async => "ok";
Future<bool> errorTask() async {
throw Exception("任务失败");
}
void main() async {
try {
// 列表形式
var results = await [delete(), copy(), errorTask()].wait;
} on ParallelWaitError<List<Object?>, List<AsyncError?>> catch (e) {
print(e.values); // 成功有值,失败为null
print(e.errors); // 成功为null,失败存放错误信息
}
// Record元组形式:支持不同类型Future
try {
final (resInt, resStr, resBool) = await (delete(), copy(), errorTask()).wait;
} on ParallelWaitError<(int?, String?, bool?), (AsyncError?, AsyncError?, AsyncError?)> catch(e) {
}
}Code language: JavaScript (javascript)
二、Stream
Stream 表示一系列连续异步数据(文件逐行读取、按钮点击事件、网络数据流)。
两种使用方式
1:await for 异步for循环(简洁,类似同步遍历)
适合有限数据流;不适合无限持续事件流(如页面点击事件),会阻塞后续代码。
import 'dart:io';
Future<void> readFileByAwaitFor() async {
var file = File("config.txt");
Stream<List<int>> input = file.openRead();
var lines = input
.transform(utf8.decoder)
.transform(const LineSplitter());
try {
await for (final line in lines) {
print("读取一行:$line");
}
print("文件读取完毕");
} catch (e) {
print("读取异常 $e");
}
}Code language: PHP (php)
2.listen() 订阅监听(适合无限事件流)
inputStream.listen(
(data) {
// 收到数据回调
},
onError: (err) {
// 发生错误
},
onDone: () {
// 流正常关闭完成
},
);Code language: JavaScript (javascript)
listen 返回
StreamSubscription,可以调用.cancel()取消订阅。
常用 Stream 操作方法
- 筛选:
where() - 截取:
take()、takeWhile() - 跳过:
skip()、skipWhile() - 获取单个元素:
first、last、single、firstWhere()
Stream 数据转换 transform()
通过转换器修改流的数据类型(典型场景:二进制流转字符串)
var lines = inputStream
.transform(utf8.decoder) // List<int> → String
.transform(const LineSplitter()); // String → 逐行字符串Code language: JavaScript (javascript)
listen() vs await for 选择建议
- 文件读取、有限序列数据 →
await for - UI事件、持续推送消息等无限流 →
.listen() - await for一旦开始,会一直等待流结束;无限事件流会造成代码卡死
Previous: dart:io