Dart中如何等待Map<int,Future<GpxCoordinates>>并获取结果Map?
问题描述
我持有一个Map<int, Future<GpxCoordinates>>对象,其中int类型的键为实体ID,Future内包含调用API获取对应实体ID数据的异步请求。我需要同时发起所有请求并等待它们完成,但当前实现返回的是List<GpxCoordinates>,而我需要的是Map<int, GpxCoordinates>。
当前无法满足需求的代码:
try { Map<int, Future<GpxCoordinates>> gpxsCoordinatesToFetch = {}; for (var tourId in event.toursIds) { gpxsCoordinatesToFetch[tourId] = gpxRepository.fetchGpxCoordinates(tourId); } // 问题:返回类型不符合需求 final gpxsCoordinates = await Future.wait(gpxsCoordinatesToFetch.values); emit(GpxsCoordinatesLoaded(coordinates: gpxsCoordinates)); } catch (e) { debugPrint(e.toString()); emit(GpxError()); }
解决方案
方法一:利用键与结果列表的顺序对应关系
Future.wait返回的列表顺序和传入的values顺序完全一致,因此可以通过原Map的键列表来一一匹配构建目标Map:
try { Map<int, Future<GpxCoordinates>> gpxsCoordinatesToFetch = {}; for (var tourId in event.toursIds) { gpxsCoordinatesToFetch[tourId] = gpxRepository.fetchGpxCoordinates(tourId); } // 保存键的顺序,和后续结果列表对应 final tourIds = gpxsCoordinatesToFetch.keys.toList(); final coordinatesList = await Future.wait(gpxsCoordinatesToFetch.values); // 构建目标Map final Map<int, GpxCoordinates> gpxsCoordinates = {}; for (int i = 0; i < tourIds.length; i++) { gpxsCoordinates[tourIds[i]] = coordinatesList[i]; } emit(GpxsCoordinatesLoaded(coordinates: gpxsCoordinates)); } catch (e) { debugPrint(e.toString()); emit(GpxError()); }
方法二:包装Future返回包含ID的结果
让每个Future返回包含实体ID和对应数据的组合,再通过这些组合直接构建Map:
try { List<Future<(int, GpxCoordinates)>> futures = []; for (var tourId in event.toursIds) { // 包装Future,使结果携带ID futures.add( gpxRepository.fetchGpxCoordinates(tourId) .then((coords) => (tourId, coords)) ); } final results = await Future.wait(futures); // 从结果列表快速构建Map final gpxsCoordinates = Map.fromEntries( results.map((res) => MapEntry(res.$1, res.$2)) ); emit(GpxsCoordinatesLoaded(coordinates: gpxsCoordinates)); } catch (e) { debugPrint(e.toString()); emit(GpxError()); }
注:如果你的Dart版本低于3.0,不支持元组语法,可以改用MapEntry或自定义类来承载ID与结果的组合。
方法三:异步串行循环(不推荐)
这种方式会逐个发起请求,失去并行请求的性能优势,仅适合特殊场景:
try { final Map<int, GpxCoordinates> gpxsCoordinates = {}; for (var tourId in event.toursIds) { // 串行执行请求,效率较低 gpxsCoordinates[tourId] = await gpxRepository.fetchGpxCoordinates(tourId); } emit(GpxsCoordinatesLoaded(coordinates: gpxsCoordinates)); } catch (e) { debugPrint(e.toString()); emit(GpxError()); }
内容的提问来源于stack exchange,提问作者E.Benedos
相关产品推荐
相关产品推荐

