Dart异步方法中等待非null值的更优雅实现方式探讨
Dart后端中等待非null值的更优实现方案
问题场景
我目前通过轮询方式等待command变量变为非null值,代码如下,但希望找到更高效的实现方案(纯Dart后端环境,无法使用Flutter的FutureBuilder):
String? command; Stream<({Message message})> detect(List<Message> messages) async* { while (command == null) { await Future.delayed(const Duration(milliseconds: 100)); } // 后续业务逻辑... }
更优方案
方案1:使用Completer(单次等待场景)
Completer是Dart异步编程中用于手动触发Future完成的工具,通过事件驱动替代轮询,避免资源浪费且响应即时。
实现代码:
final Completer<String> _commandCompleter = Completer<String>(); String? _command; // 通过setter封装赋值逻辑,确保非null值触发完成事件 set command(String? value) { _command = value; if (value != null && !_commandCompleter.isCompleted) { _commandCompleter.complete(value); } } Stream<({Message message})> detect(List<Message> messages) async* { // 等待command变为非null,无需轮询 final String targetCommand = await _commandCompleter.future; // 后续业务逻辑,使用targetCommand... }
方案2:使用StreamController(多次监听场景)
如果需要多次监听command的非null值变化,可使用广播类型的StreamController,支持多订阅者监听。
实现代码:
final StreamController<String> _commandStreamController = StreamController<String>.broadcast(); String? _command; set command(String? value) { _command = value; if (value != null) { _commandStreamController.add(value); } } Stream<({Message message})> detect(List<Message> messages) async* { // 获取第一个非null的command值 final String targetCommand = await _commandStreamController.stream.first; // 后续业务逻辑... }
方案对比
原轮询方案存在两个明显缺陷:
- 资源浪费:每隔100ms执行一次检查,即使
command早已赋值; - 响应延迟:最快需要100ms才能检测到
command的变化,无法做到即时响应。
上述两种异步通知方案均为事件驱动模式,command赋值为非null时立即触发等待逻辑,无额外资源消耗且响应即时。
内容的提问来源于stack exchange,提问作者Defarine
相关产品推荐
相关产品推荐

