Appearance
dart-stream-async-generator
1. 实验目标
用最小 Dart CLI 验证 Stream 与异步生成器(对应 docs/01-runtime-concurrency/13):
async*生成器:yield逐个产出,消费端逐条收到StreamController:手动控制事件流与关闭(done)- 手动背压:
StreamSubscription.pause()/resume()控制消费速率 await for:把 Stream 当异步序列循环消费
2. 工程要点
- 纯 Dart
bin/入口,不依赖 Flutter UI countDown(n)用async*+yield演示生成器;manualEmitter()用StreamController演示手动推送- 背压演示:
pause()后生产者事件排队,resume()后按顺序继续消费(事件不丢)
3. 关键实现速览
3.1 async* 生成器与消费
为什么看这段:展示"事件逐个产出、消费端逐个收到"的最小模型,也是 Flutter 里 StreamBuilder / RxDart 的底层。
dart
Stream<int> countDown(int n) async* {
for (var i = n; i >= 1; i--) {
await Future.delayed(const Duration(milliseconds: 200));
yield i; // 产出后,消费端 listen 回调立即触发
}
}
// 消费:await for 相当于 for-in,但每次取下一个事件会 await
await for (final v in countDown(3)) {
print('countDown 收到: $v');
}3.2 手动背压
为什么看这段:Dart Stream 默认无背压(事件进队列),pause/resume 是手动节流手段。
dart
final sub = countDown(4).listen((v) => print('[消费端] 收到 $v'));
sub.pause(); // 暂停消费,事件排队
await Future.delayed(const Duration(seconds: 2));
sub.resume(); // 恢复,按顺序继续消费4. 运行方式
bash
cd labs/dart/host
dart run bin/runtime_concurrency/stream_async_generator_demo.dart5. 预期现象
countDown(3):依次打印 3 → 2 → 1(每个间隔 200ms)manualEmitter:每 300ms 一条event#1..5,最后自动 close- 背压段:收到前几条后暂停 2 秒,
resume()后剩余事件按顺序继续(不丢)
6. 常见误区
| 误区 | 实际情况 |
|---|---|
| Stream 会自动背压 | 不会——事件进缓冲队列;要手动 pause/resume 或自行限速 |
async* 是立即执行 | 是惰性的:没有 listen 时生成器不会跑(cold stream) |
StreamController 用完不关 | 不 close() 会造成监听器永不收到 done,资源悬挂 |