Angular 6 Guard中如何从BehaviorSubject返回值?
嘿,我来帮你解决这个RxJS版本升级的问题!
首先得明确:RxJS从v6版本开始,所有操作符都必须通过pipe()方法来组合调用,不能再像旧版本那样直接在Observable/Subject实例上链式调用map()这类操作符——这也是你旧代码失效的根本原因。
看你尝试的新代码,写法本身是对的,但为什么没返回结果呢?大概率不是pipe(map())的问题,而是下面这几个点没注意到:
1. 确认你的BehaviorSubject有初始值
BehaviorSubject和普通Subject最大的区别就是它必须有初始值,而且订阅时会立即把当前最新值推送给订阅者。如果你的this.authservice.behaviorsubject()返回的BehaviorSubject没有设置初始值(比如创建时写的是new BehaviorSubject()而不是new BehaviorSubject(false)),那它可能根本没发出任何值,导致canActivate一直处于等待状态。
2. 简化你的map逻辑(不是问题,但更简洁)
你的map里的判断其实可以简化成一行,没必要写if-else:
map(x => !!x)
!!x会把任何值转换成布尔值,和你原来的逻辑完全一致。
3. 检查Subject是否正确发出了值
可以在pipe里加一个tap()操作符来调试,看看有没有值流过来:
import { tap, map } from 'rxjs/operators'; // ... canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { return this.authservice.behaviorsubject().pipe( tap(x => console.log('当前Subject值:', x)), // 调试用,看控制台有没有输出 map(x => !!x) ); }
如果控制台没输出,那说明你的Subject根本没发出值,得去检查authservice里的逻辑,是不是在某个地方没调用behaviorsubject.next(xxx)来更新状态。
4. 关于AnonymousSubject的疑问
其实AnonymousSubject是RxJS内部的一个子类,继承自Subject,它本身不会影响功能。你看到控制台显示这个类型,只是因为pipe()返回的Observable包装类型而已,不用纠结这个,重点还是看有没有值发出。
最终的正确代码示例
import { map, catchError } from 'rxjs/operators'; import { of } from 'rxjs'; import { Router } from '@angular/router'; // 记得在构造函数里注入Router constructor(private authservice: AuthService, private router: Router) {} canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { return this.authservice.behaviorsubject().pipe( map(x => !!x), catchError(() => { // 万一出错,重定向到登录页并返回false this.router.navigate(['/login']); return of(false); }) ); }
最后排查步骤
- 去authservice里确认BehaviorSubject的创建方式:
private authSubject = new BehaviorSubject<boolean>(false);(必须有初始值) - 确认在登录/登出时,调用了
this.authSubject.next(true)或this.authSubject.next(false)来更新状态 - 用
tap()调试,确认有值流到canActivate里
内容的提问来源于stack exchange,提问作者Igor

