RxJs:如何在同一Observable内获取最后发射的值
用RxJS的scan操作符实现状态留存,无需额外Subject
你需要基于Observable上一次的输出结果处理新输入,同时避免重复执行昂贵操作,完全可以用scan操作符来实现,不需要额外的BehaviorSubject。
改造后的代码示例
interface PersonInfo { name: string; data: string; } const names$ = new Subject<string[]>(); // 用scan累积状态,替代原有的BehaviorSubject const namesData$ = names$.pipe( scan((previousPersons: PersonInfo[], currentNames: string[]) => { // 保留当前names列表中存在的人员 const filteredPersons = previousPersons.filter(person => currentNames.includes(person.name) ); // 补充新增的人员,仅在首次遇到该name时调用昂贵操作 currentNames.forEach(name => { if (!filteredPersons.some(person => person.name === name)) { filteredPersons.push({ name, data: getPersonData(name) }); } }); return filteredPersons; }, [] as PersonInfo[]) // 初始状态设为空数组 ); const getPersonData = (name: string) => { // 昂贵操作,仅首次触发 console.log(`getPersonsData called by ${name}`); return name; };
为什么scan是最优解
- scan的核心逻辑就是持续累积Observable的发射值:每次新的names数组到来时,都会自动用上一次处理后的人员列表(累积值)计算新结果,完全匹配你“复用本Observable最后发射值”的需求。
- 不需要额外维护BehaviorSubject:状态由scan内部自动管理,避免了手动调用
next更新外部状态的副作用,代码更简洁可靠。 - 解决withLatestFrom的问题:scan支持设置初始值(这里是空数组),第一次names$发射时就能正常处理,不会出现“未初始化”或“永远不发射”的问题。
内容的提问来源于stack exchange,提问作者Rudy
相关产品推荐
相关产品推荐

