无法通过Resolver将多个API响应传递至组件求助
问题
我尝试从两个不同的API获取响应并合并为单个对象,传递给Resolver后再将数据送至Document组件加载,但无法正确获取响应。需要实现将多个API调用的结果合并为单个对象返回。
原代码
resolve(): Observable<any> { return new Observable(observer => { let filterValue = JSON.parse(sessionStorage.getItem('stateFilter-local')); if (filterValue?.selection?.length > 0) { delete filterValue['selection']; sessionStorage.removeItem('stateFilter-local'); sessionStorage.setItem('stateFilter-local', JSON.stringify(filterValue)); } this.service.getCOALatestLogBookID(false).subscribe({ next: (response) => { if (response['value'][0] != undefined) { let maxVaule = response['value'][0].id; this.service.getCOALatestLogBookID(true).subscribe({ next: (result) => { const spConfigValue: number = 4999; //+environment.documentsGridLimit; let lobvalue = (+maxVaule / spConfigValue); if (!Number.isInteger(lobvalue)) { lobvalue = Math.floor(lobvalue) + 1; } let array = []; let initailValue = +result['value'][0].id; let endValue = initailValue + spConfigValue; for (let f = 0; f < lobvalue; f++) { let filter = initailValue + ',' + endValue; array.push(filter); initailValue = endValue + 1; endValue = endValue + spConfigValue; } this.modelList1=[]; combineLatest(array.map(number => this.service.getCOALogBookGrid(number, spConfigValue.toString()))).subscribe((res: any) => { res.map(item => { console.log('forkJoin - ' + this.modelList.length + ' - ' + item?.['value'].length); this.modelList.push(item); let dd = --array.length; if (dd == 0) { const response = { spListMaxId: maxVaule, spListMinId: result['value'][0].id, model: this.modelList1 } this.modelList1=[...this.modelList]; observer.next(response); observer.complete(); } }); }); } }); } } }); this.service.getLatestLogBookID(false).subscribe({ next: (response) => { if (response['value'][0] != undefined) { let maxVaule = response['value'][0].id; this.service.getLatestLogBookID(true).subscribe({ next: (result) => { const spConfigValue: number = 4999; //+environment.documentsGridLimit; let lobvalue = (+maxVaule / spConfigValue); if (!Number.isInteger(lobvalue)) { lobvalue = Math.floor(lobvalue) + 1; } let array = []; let initailValue = +result['value'][0].id; let endValue = initailValue + spConfigValue; for (let f = 0; f < lobvalue; f++) { let filter = initailValue + ',' + endValue; array.push(filter); initailValue = endValue + 1; endValue = endValue + spConfigValue; } combineLatest(array.map(number => this.service.getLogBookGrid(number, spConfigValue.toString()))).subscribe((res: any) => { res.map(item => { console.log('forkJoin - ' + this.modelList.length + ' - ' + item?.['value'].length); this.modelList1.push(item); let dd = --array.length; if (dd == 0) { const response = { spListMaxId: maxVaule, spListMinId: result['value'][0].id, model: this.modelList1 } observer.next(response); observer.complete(); console.log(this.modelList1,"array") } }); }); } }); } } }); }); }
问题分析
- 嵌套订阅形成回调地狱,逻辑混乱,且没有错误处理,单个API失败会导致整个流程挂起
- 两个并行的API流各自独立调用
observer.next()和observer.complete(),Resolver会收到两次结果,无法合并成单个对象 - 使用共享变量
modelList、modelList1,两个流同时修改会导致数据冲突 - 手动判断数组长度来触发完成,逻辑冗余且容易出错
解决方案
用RxJS操作符重构代码,避免嵌套订阅,同时合并两个流的结果:
import { forkJoin, switchMap, map, catchError, of } from 'rxjs'; resolve(): Observable<any> { // 处理sessionStorage逻辑 let filterValue = JSON.parse(sessionStorage.getItem('stateFilter-local') || '{}'); if (filterValue?.selection?.length > 0) { delete filterValue.selection; sessionStorage.setItem('stateFilter-local', JSON.stringify(filterValue)); } // 封装COA相关API请求逻辑 const fetchCOAData$ = this.service.getCOALatestLogBookID(false).pipe( switchMap(coaMaxRes => { if (!coaMaxRes?.value?.[0]) return of(null); const maxValue = coaMaxRes.value[0].id; return this.service.getCOALatestLogBookID(true).pipe( switchMap(coaMinRes => { if (!coaMinRes?.value?.[0]) return of(null); const spConfigValue = 4999; const minValue = coaMinRes.value[0].id; const lobValue = Math.ceil(Number(maxValue) / spConfigValue); // 生成批量请求数组 const requests = []; let initialValue = Number(minValue); for (let f = 0; f < lobValue; f++) { const endValue = initialValue + spConfigValue; requests.push(this.service.getCOALogBookGrid(`${initialValue},${endValue}`, spConfigValue.toString())); initialValue = endValue + 1; } // 并行执行所有COA请求,合并结果 return forkJoin(requests).pipe( map(coaModels => ({ coaSpListMaxId: maxValue, coaSpListMinId: minValue, coaModel: coaModels.flatMap(item => item.value || []) })) ); }) ); }), catchError(err => { console.error('COA数据请求失败:', err); return of(null); }) ); // 封装普通LogBook相关API请求逻辑 const fetchLogBookData$ = this.service.getLatestLogBookID(false).pipe( switchMap(logMaxRes => { if (!logMaxRes?.value?.[0]) return of(null); const maxValue = logMaxRes.value[0].id; return this.service.getLatestLogBookID(true).pipe( switchMap(logMinRes => { if (!logMinRes?.value?.[0]) return of(null); const spConfigValue = 4999; const minValue = logMinRes.value[0].id; const lobValue = Math.ceil(Number(maxValue) / spConfigValue); // 生成批量请求数组 const requests = []; let initialValue = Number(minValue); for (let f = 0; f < lobValue; f++) { const endValue = initialValue + spConfigValue; requests.push(this.service.getLogBookGrid(`${initialValue},${endValue}`, spConfigValue.toString())); initialValue = endValue + 1; } // 并行执行所有LogBook请求,合并结果 return forkJoin(requests).pipe( map(logModels => ({ logSpListMaxId: maxValue, logSpListMinId: minValue, logModel: logModels.flatMap(item => item.value || []) })) ); }) ); }), catchError(err => { console.error('LogBook数据请求失败:', err); return of(null); }) ); // 合并两个流的结果,返回单个对象 return forkJoin([fetchCOAData$, fetchLogBookData$]).pipe( map(([coaData, logData]) => ({ coaData, logData })), catchError(err => { console.error('数据合并失败:', err); return of({ coaData: null, logData: null }); }) ); }
关键改进点
- 用
switchMap替代嵌套订阅,扁平化异步逻辑,避免回调地狱 - 用
forkJoin并行执行批量API请求,确保所有请求完成后再返回结果 - 将COA和LogBook的请求逻辑拆分,各自处理后再合并为单个对象返回
- 移除共享变量,用数据流传递数据,避免数据冲突
- 添加
catchError处理每个环节的错误,防止单个请求失败导致Resolver挂起 - 对返回的模型数据做平铺处理,方便组件直接使用
内容的提问来源于stack exchange,提问作者Balachandar K
相关产品推荐
相关产品推荐

