Angular RxJS过滤undefined用户值 仅有效用户触发积分接口调用
RxJS流拦截undefined值避免无效接口调用方案
场景说明
已登录指定用户账号的业务场景下,需要先获取当前用户ID,再调用REST API查询该用户的积分。
初始实现代码
getPoints(): Observable<number> { return this.userAccount.get().pipe( switchMap(userOrUndefined => { console.log("User retrieved:" + userOrUndefined?.customerId) return this.pointsRetrievalService.getPoints(userOrUndefined); }), catchError(error => of(error)) ) }
其中注入的userAccount类型为UserAccountFacade,类定义如下:
import { Observable } from 'rxjs'; import { User } from '../model/user.model'; import * as i0 from "@angular/core"; export declare abstract class UserAccountFacade { abstract get(): Observable<User | undefined>; static ɵfac: i0.ɵɵFactoryDeclaration<UserAccountFacade, never>; static ɵprov: i0.ɵɵInjectableDeclaration<UserAccountFacade>; }
问题表现
调用userAccount.get().subscribe(...)时,流会首先发射undefined值,直接触发积分查询服务的无效调用,待真实用户对象加载完成后才会发射有效值,触发第二次有效调用,控制台日志如下:
Retrieving user:undefined pointsRetrievalService called Retreiving user:eb6cb3de-4107-4ef9-9d95-e0fb83e5c200 pointsRetrievalService called
核心需求:忽略流中返回的undefined用户值,仅当this.userAccount.get()返回第一个非undefined的有效用户时,才调用getPoints积分查询服务。
修复方案
使用RxJS内置的filter操作符拦截无效的undefined值,只有有效用户对象进入流时才会执行后续的积分查询逻辑。
- 首先从rxjs导入需要的操作符:
import { filter, switchMap, catchError, of } from 'rxjs';
- 修改
getPoints方法,在switchMap前加入过滤逻辑:
getPoints(): Observable<number> { return this.userAccount.get().pipe( // 过滤undefined值,通过类型守卫收窄流类型为User filter((userOrUndefined): userOrUndefined is User => Boolean(userOrUndefined)), switchMap(validUser => { console.log("User retrieved:" + validUser.customerId) return this.pointsRetrievalService.getPoints(validUser); }), catchError(error => of(error)) ) }
逻辑说明
filter操作符会校验流中每一个发射的值,Boolean(userOrUndefined)为false的undefined值会被直接拦截,不会进入后续switchMap逻辑,从根源上避免无效的积分接口调用- 写法中加入了TS类型守卫,过滤后流内的值类型会自动收窄为
User,后续代码不需要再做可选链判空处理
如果需要仅在第一次获取到有效用户时查询一次积分,后续用户信息变更不再重复触发查询,只需在filter后追加take(1)操作符即可:
import { filter, take, switchMap, catchError, of } from 'rxjs'; getPoints(): Observable<number> { return this.userAccount.get().pipe( filter((userOrUndefined): userOrUndefined is User => Boolean(userOrUndefined)), // 取到第一个有效用户后自动终止流,不再响应后续数据发射 take(1), switchMap(validUser => { console.log("User retrieved:" + validUser.customerId) return this.pointsRetrievalService.getPoints(validUser); }), catchError(error => of(error)) ) }
内容的提问来源于stack exchange,提问作者Joel
相关产品推荐
相关产品推荐

