Angular 12中async管道未订阅导致加载状态异常问题
问题原因与解决方案
根本原因
你使用了普通的Subject传递token,但普通Subject不会缓存已发送的值。
你的代码执行时序如下:
- 初始化
userInfo$,它依赖getUserInfo这个Subject - 订阅
route.paramMap,拿到token后调用getUserInfo.next(token) - 组件视图渲染完成后,async管道才会订阅
userInfo$
此时next(token)已经执行完毕,普通Subject不会把之前发送的值推送给新订阅的async管道,导致async管道一直收不到数据,页面停留在loading状态。而你手动调用subscribe()是在next(token)之前完成订阅的,所以能正常获取响应。
解决方案
有两种常用修复方式:
方式1:替换为BehaviorSubject
BehaviorSubject会缓存最新的一个值,新订阅者订阅时会立即收到当前的最新值。修改代码:
// 替换原Subject定义 getUserInfo: BehaviorSubject<string> = new BehaviorSubject<string>('');
这样async管道订阅userInfo$时,会立即获取到BehaviorSubject中当前的token值,触发后续服务调用,页面就能正常渲染数据。
方式2:移除额外Subject,直接基于路由参数构建Observable
既然token来自路由参数,可直接将路由参数的Observable与数据请求逻辑串联,省去中间Subject:
ngOnInit(): void { this.userInfo$ = this.route.paramMap.pipe( map(params => params.get('token')), // 过滤null值,避免无效请求 filter(token => !!token), mergeMap(token => this.service.getKey(token).pipe( map(res => ({ user: res.client, info: res.info })) )), tap(res => console.log(res)) ); }
这种方式更简洁,还避免了Subject带来的时序问题,async管道订阅后会自动触发路由参数读取与数据请求。
内容的提问来源于stack exchange,提问作者Igor Cantele
相关产品推荐
相关产品推荐

