mcpField
D
dart-async-programming

dart-async-programming

github.com/dart-lang开发53270 次安装2 周前更新
代码仓库

关于 dart-async-programming

指导开发者使用 Future 和 Stream 编写 Dart 异步代码,重点包括清晰的流程、错误处理、并发执行及流生命周期管理。

主要功能

  1. 01优先使用 async 和 await
  2. 02通过 try-catch 处理错误
  3. 03并发执行互不依赖的 Future
  4. 04使用 await for 消费流
  5. 05关闭 StreamController 实例

适用场景

  1. 01实现异步数据获取
  2. 02并发执行互不依赖的请求
  3. 03按顺序处理流事件
  4. 04避免 StreamController 资源泄漏

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dart-lang/skills --skill dart-async-programming

安装后在 Claude Code 中输入/dart-async-programming确认已加载。

详细介绍

编写异步 Dart 代码

目录

核心指南

使用现代、声明式模式编写异步 Dart 代码。避免使用基于回调的旧式方法。假设所有网络、文件 I/O 和数据库操作都是异步的。

  • 使用 async/await:始终优先使用 async 和 await,而不是原始的 .then()、.catchError() 或 .whenComplete() 链式调用。这样可以简化执行流程并提升可读性。
  • 妥善处理错误:将所有 await 调用放在 try-catch 块中,以处理异常。不要依赖未处理的 Future 拒绝。
  • 并发执行:使用 Future.wait 同时启动并等待多个相互独立的 Future,而不是依次等待。
  • 按顺序消费 Stream:消费 Stream 时,优先使用 await for,而不是 .forEach() 或 .listen(),除非你确实需要低级订阅管理(例如暂停或恢复)。
  • 防止内存泄漏:不再需要 StreamController 时,或所属类被释放时,务必调用 .close()。

处理 Future

顺序执行与并发执行

如果操作之间存在依赖关系,应依次等待。如果操作相互独立,则应同时启动,以优化执行时间。

顺序执行(存在依赖):

final user = await fetchUser(id);
final profile = await fetchProfile(user.profileId);

并发执行(相互独立):

final results = await Future.wait([
  fetchUserData(id),
  fetchUserPreferences(id),
  fetchUserPermissions(id),
]);
错误处理

在 async 函数中始终使用标准的 try-catch-finally 块。

try {
  final data = await fetchData();
  process(data);
} on NetworkException catch (e) {
  handleNetworkError(e);
} catch (e) {
  handleGenericError(e);
} finally {
  cleanupResources();
}

管理 Stream

消费 Stream

使用异步 for 循环(await for)按顺序处理 Stream 事件。它会自动处理 Stream 完成,并能与 try-catch 错误处理机制无缝配合。

try {
  await for (final chunk in fileStream) {
    processChunk(chunk);
  }
} catch (e) {
  logError('Stream processing failed: $e');
}
创建和管理 Stream

使用 StreamController 创建自定义 Stream 时,请确保妥善管理其生命周期,以避免内存泄漏。

class DataProvider {
  final _controller = StreamController<Data>.broadcast();

  Stream<Data> get dataStream => _controller.stream;

  void updateData(Data newData) {
    if (!_controller.isClosed) {
      _controller.add(newData);
    }
  }

  void dispose() {
    _controller.close(); // Mandatory cleanup
  }
}

工作流

任务进度:实现异步数据获取器

复制此清单,以跟踪异步数据获取逻辑的实现进度:

  • 确定所需操作是顺序执行还是相互独立。
  • 为函数添加 async 关键字,并返回 Future<T>。
  • 将异步操作放在 try-catch 块中。
  • 如果操作相互独立,使用 Future.wait 将 Future 组合起来。
  • 如果操作需要顺序执行,则对每个步骤使用 await。
  • 使用 on ExceptionType catch (e) 处理特定异常。
  • 运行验证器 -> 检查错误 -> 修复未处理的 Promise 拒绝。
任务进度:实现 Stream 消费者

复制此清单,以跟踪 Stream 消费逻辑的实现进度:

  • 确认 Stream 来源(单订阅还是广播)。
  • 将消费函数标记为 async。
  • 将消费逻辑放在 try-catch 块中。
  • 实现 await for 循环来遍历 Stream。
  • 确保在满足特定终止条件时跳出循环或返回。
  • 如果管理 StreamController,请实现 dispose() 或 close() 方法。

示例

反面模式与最佳实践:Future

反面模式(请勿使用):

Future<void> loadUserData() {
  return fetchUser()
    .then((user) {
      return fetchProfile(user.id)
        .then((profile) {
          print('User: ${user.name}, Profile: ${profile.status}');
        });
    })
    .catchError((error) {
      print('Error: $error');
    });
}

最佳实践:

Future<void> loadUserData() async {
  try {
    final user = await fetchUser();
    final profile = await fetchProfile(user.id);
    print('User: ${user.name}, Profile: ${profile.status}');
  } catch (error) {
    print('Error: $error');
  }
}
反面模式与最佳实践:Stream

反面模式(请勿使用):

void processEvents(Stream<Event> eventStream) {
  eventStream.listen(
    (event) => handleEvent(event),
    onError: (error) => print('Error: $error'),
  );
}

最佳实践:

Future<void> processEvents(Stream<Event> eventStream) async {
  try {
    await for (final event in eventStream) {
      handleEvent(event);
    }
  } catch (error) {
    print('Error: $error');
  }
}

相关技能

  • dart-idiomatic-usage
  • dart-concurrency-isolates

评论

支持 Markdown