dart:async 库

dart:async 提供 Dart 异步编程核心能力:Future、Stream

小提示:

  1. 使用 Future / Stream 不一定需要手动 import dart:async,dart:core 已经导出;
  2. 如果要使用 StreamControllerStreamSubscriptionParallelWaitError 等类型,需要显式导入:
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()
  • 获取单个元素:firstlastsinglefirstWhere()

Stream 数据转换 transform()

通过转换器修改流的数据类型(典型场景:二进制流转字符串)

var lines = inputStream
    .transform(utf8.decoder)       // List<int> → String
    .transform(const LineSplitter()); // String → 逐行字符串Code language: JavaScript (javascript)

listen() vs await for 选择建议

  1. 文件读取、有限序列数据 → await for
  2. UI事件、持续推送消息等无限流.listen()
  3. await for一旦开始,会一直等待流结束;无限事件流会造成代码卡死

Previous:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注