如何使用async/await从subscribe中返回数据并执行后续操作
问题场景
父组件从后端获取数据后,过滤出包含mbl_vessels属性的条目,通过Service发送给孙组件;孙组件接收数据后需要处理并调用地图绘制相关函数,但由于RxJS订阅的异步特性,订阅外部的函数会提前执行并拿到undefined,仅订阅内部能获取到正常数据。
现有代码
Service
sendDataToMap(dataToMap: []) { this.send_data.next(dataToMap); } reciveDataToMap(): Observable<any>{ return this.send_data.asObservable(); } getDataToRenderOnMap(dataToMap){ this.routesList.push(data?.mbl_vessels?.path); const currentPos: number[] = Object.values(data?.mbl_vessels?.currentPosition); this.pointsToFit.push(currentPos); const marker: IMarker = { transportType: data?.quote?.transportationMode, currentPosition: currentPos }; this.markersToRender.push(marker); } return { routesList: this.routesList, pointsToFit: this.pointsToFit, markersToRender: this.markersToRender };
父组件
this.elementsToMap = elementsReq.data.filter(item => item.hasOwnProperty('mbl_vessels')); this.miniMapService.sendDataToMap(this.elementsToMap);
孙组件
ngAfterViewInit() { this.loadMap(MapStyles.COLOR_STYLE); this.loadMapControls(); this.prepareDataToMap(); // 期望在订阅完成后执行,但当前会提前拿到undefined this.setLineStyle(LinePathColor.TO_COLOR, geoData); this.setCustomMarkers(); this.setMarkerForBounding(shipmentsDataPosition); this.cdref.detectChanges(); } prepareDataToMap(){ this.miniMapService.reciveDataToMap().subscribe((data) => { this.dataToMap = data; this.dataReturned = this.miniMapService.getDataToRenderOnMap(this.dataToMap); }); } setLineStyle(colorPath: string, route?) { this.mapa.on('load', () => { this.mapa.addSource('route', { 'type': 'geojson', 'data': { 'type': 'Feature', 'properties': {}, 'geometry': { 'type': 'LineString', 'coordinates': route } } }); this.mapa.addLayer({ 'id': 'route', 'type': 'line', 'source': 'route', 'layout': { 'line-join': 'round', 'line-cap': 'round' }, 'paint': { 'line-color': colorPath, 'line-width': 2, "line-dasharray": [0.2, 2] } }); }); }
解决方案
1. 修复Service数据污染问题
原Service的getDataToRenderOnMap使用类成员变量存储数据,会导致多次调用时数据累加,改用局部变量避免污染:
getDataToRenderOnMap(dataToMap){ // 改用局部变量,避免跨调用的数据污染 const routesList = []; const pointsToFit = []; const markersToRender = []; dataToMap.forEach((data) => { routesList.push(data?.mbl_vessels?.path); const currentPos: number[] = Object.values(data?.mbl_vessels?.currentPosition); pointsToFit.push(currentPos); const marker: IMarker = { transportType: data?.quote?.transportationMode, currentPosition: currentPos }; markersToRender.push(marker); }); return { routesList, pointsToFit, markersToRender }; }
2. 调整孙组件执行逻辑,确保数据就绪后调用地图函数
将地图相关函数的调用移至订阅内部,同时确保地图加载完成后再处理数据:
ngAfterViewInit() { this.loadMap(MapStyles.COLOR_STYLE); // 等待地图加载完成后再初始化控件和处理数据 this.mapa.on('load', () => { this.loadMapControls(); this.prepareDataToMap(); this.cdref.detectChanges(); }); } prepareDataToMap(){ this.miniMapService.reciveDataToMap().subscribe((data) => { this.dataToMap = data; this.dataReturned = this.miniMapService.getDataToRenderOnMap(this.dataToMap); // 数据处理完成后,调用地图绘制函数 this.setLineStyle(LinePathColor.TO_COLOR, this.dataReturned.routesList); this.setCustomMarkers(this.dataReturned.markersToRender); this.setMarkerForBounding(this.dataReturned.pointsToFit); }); } // 优化setLineStyle,支持批量添加路线 setLineStyle(colorPath: string, routes?: any[]) { if (!routes || routes.length === 0) return; routes.forEach((route, index) => { // 使用唯一ID避免source和layer重复 const sourceId = `route-${index}`; const layerId = `route-layer-${index}`; this.mapa.addSource(sourceId, { 'type': 'geojson', 'data': { 'type': 'Feature', 'properties': {}, 'geometry': { 'type': 'LineString', 'coordinates': route } } }); this.mapa.addLayer({ 'id': layerId, 'type': 'line', 'source': sourceId, 'layout': { 'line-join': 'round', 'line-cap': 'round' }, 'paint': { 'line-color': colorPath, 'line-width': 2, "line-dasharray": [0.2, 2] } }); }); }
关键修改说明
- 异步逻辑对齐:将地图函数移至订阅内部,确保只有当数据接收并处理完成后才执行,解决
undefined问题。 - 地图加载时机:通过
mapa.on('load')确保地图初始化完成后再处理数据,避免地图未就绪时调用API报错。 - 数据隔离:Service改用局部变量存储处理结果,避免多次订阅时数据重复累加。
- 批量路线支持:修改
setLineStyle循环处理路线数组,适配多路线场景。
内容的提问来源于stack exchange,提问作者Pedro Miguel Pimienta Morales
相关产品推荐
相关产品推荐

