Dart中使用yield*转发广播流未达预期,求原因及解决方法
问题原因分析
1. 执行顺序导致订阅时机滞后
main函数的代码是同步执行的:当调用getStream().listen(...)时,生成器会立即执行到yield 1,但yield* controller.stream对广播流的订阅操作,是在同步栈后续流程中完成的。而controller.add(2)和controller.close()是在listen()调用之后立刻同步执行的——此时广播流的订阅还未建立,2这个事件会被广播流直接丢弃(因为当前无有效订阅者)。
2. 广播流的事件特性
广播流(broadcast stream)的核心规则是:
- 无订阅者时发送的事件会直接丢弃;
- 新订阅者只能收到订阅建立之后发送的事件,不会缓存之前的事件。
当生成器通过yield*完成对广播流的订阅时,广播流已经执行了close()操作,因此生成器只能收到done信号,无法获取之前发送的2。
验证修改方案
将发送事件和关闭操作放到微任务队列,等待订阅完成后再执行,即可得到预期输出:
import 'dart:async'; final controller = StreamController<int>.broadcast(); Stream<int> getStream() async* { yield 1; yield* controller.stream; } void main() { controller.add(0); getStream().listen( (event) => print('BC Event: $event'), onDone: () => print('BC Done'), onError: (error) => print(error), ); // 延迟到微任务执行,确保订阅已建立 Future.microtask(() { controller.add(2); controller.close(); }); }
此时输出:
BC Event: 1 BC Event: 2 BC Done
内容的提问来源于stack exchange,提问作者nod
相关产品推荐
相关产品推荐

