Asynchronous async*是否延迟调用该函数?
在为我的项目编写一些单元测试时,我遇到了一个有趣的问题 以下是用户可用于放置标记的地图:Asynchronous async*是否延迟调用该函数?,asynchronous,dart,generator,Asynchronous,Dart,Generator,在为我的项目编写一些单元测试时,我遇到了一个有趣的问题 以下是用户可用于放置标记的地图: class DomainMap { static const _DEFAULT_COORDINATE = const Coordinate(40.73, -73.93); final ReverseGeocodingStrategy _geocodingStrategy; final RouteDefinitionStrategy _assemblyStrategy; final List&
class DomainMap {
static const _DEFAULT_COORDINATE = const Coordinate(40.73, -73.93);
final ReverseGeocodingStrategy _geocodingStrategy;
final RouteDefinitionStrategy _assemblyStrategy;
final List<_IdentifiedCoordinate> _addressed = [];
final List<Coordinate> _markers = [];
final _Route _route = _Route();
Coordinate get defaultCoordinate => _DEFAULT_COORDINATE;
DomainMap(this._geocodingStrategy, this._assemblyStrategy);
Stream<MarkersUpdateEvent> mark(Coordinate coordinate) async* {
_markers.add(coordinate);
yield _assembleMarkersUpdate();
final Address address = await _geocodingStrategy.geocode(coordinate);
_addressed.add(_IdentifiedCoordinate(coordinate, address));
if (_addressed.length > 1) {
final Iterable<Coordinate> assembledPolyline =
await _assemblyStrategy.buildRoute(BuiltList(_addressed
.map((identifiedCoordinate) => identifiedCoordinate.address)));
assembledPolyline.forEach(_route.add);
yield _assembleMarkersUpdate();
}
}
MarkersUpdateEvent _assembleMarkersUpdate() =>
MarkersUpdateEvent(BuiltList.from(_markers), _route.readOnly);
}
class _Route {
final List<Coordinate> _points = [];
Iterable<Coordinate> get readOnly => BuiltList(_points);
void add(final Coordinate coordinate) => _points.add(coordinate);
void addAll(final Iterable<Coordinate> coordinate) => _points.addAll(coordinate);
}
当我像那样运行它时,测试失败,并说流只发出一个值—一个仅带有标记的更新事件字段不为空,其中只包含第二个坐标。但是当我取消对forEach的注释时,测试通过了
据我所知-async*
方法在流的值未被请求之前不会被调用,所以当调用forEach
时,函数将一直执行到最后。因此,如果我请求所有流的(从第一次调用返回的)值—方法执行,标记
列表填充,第二次执行以预期状态执行
我是否正确理解了async*
语义?这里有没有一种方法可以让这个函数变得更急切而不是懒惰(我不想请求不需要的流的值)?是的,async*
在您对返回的流调用listen
后,会懒洋洋地调用这个函数。如果你从来不听,那么什么也不会发生。
它甚至异步执行,而不是直接响应listen
调用
因此,如果您确实需要一些事情发生,但可能只需要查看响应,那么您就不能使用async*
函数来完成这些事情
您可能想要做的是有条件地填充流,但前提是流确实被监听。
这是一个非传统的操作序列,与async*
甚至async
语义不匹配。
您必须为操作的完成做好准备,然后再监听流。这建议将操作分为两部分,一部分用于请求,另一部分用于响应,并在两者之间共享未来,这意味着两次监听同一未来,这是一种明显的非异步行为
我建议将流行为分离出来,并为此使用StreamController
Stream<MarkersUpdateEvent> mark(Coordinate coordinate) {
var result = StreamController<MarkersUpdateEvent>();
() async {
_markers.add(coordinate);
result.add(_assembleMarkersUpdate());
final Address address = await _geocodingStrategy.geocode(coordinate);
_addressed.add(_IdentifiedCoordinate(coordinate, address));
if (_addressed.length > 1) {
final Iterable<Coordinate> assembledPolyline =
await _assemblyStrategy.buildRoute(BuiltList(_addressed
.map((identifiedCoordinate) => identifiedCoordinate.address)));
assembledPolyline.forEach(_route.add);
result.add(_assembleMarkersUpdate());
}
result.close();
}().catchError(result.addError);
return result.stream;
}
流标记(坐标){
var result=StreamController();
()异步{
_标记。添加(坐标);
添加(_assembleMarkersUpdate());
最终地址=等待地理编码策略地理编码(坐标);
_地址。添加(_标识的坐标(坐标,地址));
如果(_addressed.length>1){
最终可拼接多段线=
等待装配策略。构建路线(构建列表
.map((identifiedCoordinate)=>identifiedCoordinate.address));
集合多段线.forEach(_route.add);
添加(_assembleMarkersUpdate());
}
result.close();
}().catchError(result.addError);
返回result.stream;
}
这样,程序逻辑独立于是否有人监听流而运行。您仍然需要缓冲所有流事件。没有真正的方法可以避免这种情况,除非您可以在以后计算它们,因为您不知道何时有人可能会侦听返回的流。它不必在返回时立即发生。是的,async*
在对返回的流调用listen
后,延迟调用该函数。如果你从来不听,那么什么也不会发生。
它甚至异步执行,而不是直接响应listen
调用
因此,如果您确实需要一些事情发生,但可能只需要查看响应,那么您就不能使用async*
函数来完成这些事情
您可能想要做的是有条件地填充流,但前提是流确实被监听。
这是一个非传统的操作序列,与async*
甚至async
语义不匹配。
您必须为操作的完成做好准备,然后再监听流。这建议将操作分为两部分,一部分用于请求,另一部分用于响应,并在两者之间共享未来,这意味着两次监听同一未来,这是一种明显的非异步行为
我建议将流行为分离出来,并为此使用StreamController
Stream<MarkersUpdateEvent> mark(Coordinate coordinate) {
var result = StreamController<MarkersUpdateEvent>();
() async {
_markers.add(coordinate);
result.add(_assembleMarkersUpdate());
final Address address = await _geocodingStrategy.geocode(coordinate);
_addressed.add(_IdentifiedCoordinate(coordinate, address));
if (_addressed.length > 1) {
final Iterable<Coordinate> assembledPolyline =
await _assemblyStrategy.buildRoute(BuiltList(_addressed
.map((identifiedCoordinate) => identifiedCoordinate.address)));
assembledPolyline.forEach(_route.add);
result.add(_assembleMarkersUpdate());
}
result.close();
}().catchError(result.addError);
return result.stream;
}
流标记(坐标){
var result=StreamController();
()异步{
_标记。添加(坐标);
添加(_assembleMarkersUpdate());
最终地址=等待地理编码策略地理编码(坐标);
_地址。添加(_标识的坐标(坐标,地址));
如果(_addressed.length>1){
最终可拼接多段线=
等待装配策略。构建路线(构建列表
.map((identifiedCoordinate)=>identifiedCoordinate.address));
集合多段线.forEach(_route.add);
添加(_assembleMarkersUpdate());
}
result.close();
}().catchError(result.addError);
返回result.stream;
}
这样,程序逻辑独立于是否有人监听流而运行。您仍然需要缓冲所有流事件。没有真正的方法可以避免这种情况,除非您可以在以后计算它们,因为您不知道何时有人可能会侦听返回的流。它不必在返回时立即发生