使用async/await时无法在stream代码块外打印获取的值如何解决
问题根因
代码拿不到值的核心问题是对Stream.listen的异步逻辑理解错误:
channel.stream.listen(...)调用后会立刻返回StreamSubscription订阅对象,不会等待流推送数据,给这个方法加await没有任何作用,注册完监听回调代码就会直接往下执行- 流什么时候推送数据是完全异步的,写在listen后面的打印逻辑执行时,流的回调还没触发,外部定义的
response变量还没被赋值,自然打印不出内容 - 在listen回调里给外层
response赋值的写法本身存在时序风险,哪怕后续回调触发赋值了,外面的打印和返回逻辑早就执行完了,根本拿不到更新后的值
修复方法
根据业务场景二选一即可:
- 场景1:只需要拿WebSocket返回的第一条响应数据
不要用listen注册监听,直接await流的first属性等待第一条数据返回即可,参考代码:getMarkets() async { final channel = IOWebSocketChannel.connect( Uri.parse('xxxx'), ); channel.sink.add('{"xxx":"brief", "xxx": "basic"}'); // 等待流的第一条推送数据 final response = await channel.stream.first; // 此处可正常打印获取到的值 print('--->>>respomseee111 $response'); // 用完记得关闭WebSocket连接 channel.sink.close(); return response; // 如果需要转map就放开下面的注释 // return response.map((item) => item.toMap()); } - 场景2:需要持续接收WebSocket的所有推送数据
所有依赖流数据的逻辑都要放到流的处理回调里,推荐用await for语法遍历流事件,参考代码:getMarkets() async { final channel = IOWebSocketChannel.connect( Uri.parse('xxxx'), ); channel.sink.add('{"xxx":"brief", "xxx": "basic"}'); // 持续遍历流的所有推送 await for (final response in channel.stream) { // 每收到一条推送就会进入该逻辑块 print('--->>>收到推送数据 $response'); // 所有数据处理、值返回的逻辑都写在这里即可 } // 错误处理可以加catchError捕获流异常 }
注意:不要尝试在流监听的外部作用域拿回调里赋值的变量,异步回调的执行时序永远晚于当前同步代码块的执行,这种写法100%会拿不到预期值。
内容的提问来源于stack exchange,提问作者md gouse
相关产品推荐
相关产品推荐

