如何对Observable中的数组做映射,合并多个Observable的最新值?
问题原因
原代码存在3个核心错误:
- 误用同步
map操作符处理异步流:map仅做同步值转换,不会等待内部异步Observable emit值,你在回调内调用subscribe的返回值完全不会被外层接收,且内部遍历食物的回调没有显式返回值,自然得到全是undefined的空值数组。 - 自定义的三个
Subject没有发送任何值:你没有调用getCookById这类业务接口获取真实的Observable,手动创建的Subject从未调用next推送数据,combineLatest永远不会触发回调。 - 没有对高阶Observable做展平处理:数组中每个食物项的信息组合本身就是一个Observable,需要用RxJS的展平操作符、合并操作符处理后才能得到最终的数组结果。
你提到的combineLatest是可以用的,用来组合单个食物项对应的三个并行请求的最新值完全符合需求。
正确实现代码
import { combineLatest, forkJoin, switchMap, map, take } from 'rxjs'; const foodObservable = new Subject(); foodObservable.pipe( // 用switchMap展平外层的食物数组流,切换到内层的合并请求流 switchMap(foodItems => { // 遍历每个食物项,生成每个项对应的信息组合Observable const itemObs = foodItems.map(foodItem => { // 调用真实业务接口获取三个对应的Observable const cook$ = getCookById(foodItem.cook.id); const kitchen$ = getKitchenById(foodItem.kitchen.id); const knife$ = getKnifeById(foodItem.knife.id); // 用combineLatest组合三个流,返回结构正确的对象 return combineLatest([cook$, kitchen$, knife$]).pipe( // 如果是热Observable不会自动完成,加take(1)取第一次结果即可 take(1), map(([cook, kitchen, knife]) => ({ foodItem, cook, kitchen, knife })) ) }) // 用forkJoin等待所有食物项的流都完成,返回结果数组 return forkJoin(itemObs); }) ).subscribe(foodPreparationArray=>{ console.log(foodPreparationArray) // 符合预期的数组 })
逻辑说明
- 外层收到食物数组后,先为每个食物项生成一个
combineLatest流,负责拉取对应三个关联信息并组装成目标结构对象。 - 用
forkJoin合并所有食物项的流,等待所有项的信息都拉取完成后,统一推送完整的结果数组。 - 用
switchMap把外层的食物数组流,切换为内层forkJoin返回的数组结果流,直接在subscribe中拿到最终数据。
提示:如果你的
getCookById这类接口是请求完成就自动结束的冷Observable(比如普通Http请求),可以去掉上面代码中的take(1)。
内容的提问来源于stack exchange,提问作者Joseph Allain
相关产品推荐
相关产品推荐

