【发布时间】:2016-09-23 12:18:43
【问题描述】:
我在 Angular 2 应用程序中遇到了一个异步性的棘手问题。
当应用程序在用户的浏览器中重新加载/引导时,我基本上是在尝试从后端重新补充/重新加载信息(想想 F5/刷新)。问题是,在后端异步方法返回结果之前,会调用路由器守卫并阻塞...
我从根组件的ngOnInit方法重新加载信息如下:
来自根组件:
ngOnInit() {
//reloadPersonalInfo returns an Observable
this.sessionService.reloadPersonalInfo()
.subscribe();
}
来自sessionService:
reloadPersonalInfo() {
//FIRST: the app execution flow gets here
let someCondition: boolean = JSON.parse(localStorage.getItem('someCondition'));
if (someCondition) {
return this.userAccountService.retrieveCurrentUserAccount()
.switchMap(currentUserAccount => {
//THIRD: and finally, the execution flow will get there and set the authenticated state to true (unfortunately too late)...
this.store.dispatch({type: SET_AUTHENTICATED});
this.store.dispatch({type: SET_CURRENT_USER_ACCOUNT, payload: currentUserAccount});
return Observable.of('');
});
}
return Observable.empty();
}
麻烦的是我有一个路由器CanActivate守卫如下:
canActivate() {
//SECOND: then the execution flow get here and because reloadPersonalInfo has not completed yet, isAuthenticated will return false and the guard will block and redirect to '/signin'
const isAuthenticated = this.sessionService.isAuthenticated();
if (!isAuthenticated) {
this.router.navigate(['/signin']);
}
return isAuthenticated;
}
来自sessionService的isAuthenticated方法:
isAuthenticated(): boolean {
let isAuthenticated = false;
this.store.select(s => s.authenticated)
.subscribe(authenticated => isAuthenticated = authenticated);
return isAuthenticated;
}
回顾一下:
- 首先:
sessionService上的reloadPersonalInfo方法由根组件ngOnInit调用。执行流程进入该方法。 - SECOND:在此期间,Router Guard 被调用并看到
authenticated的状态为false(因为reloadPersonalInfo尚未完成,因此未将authenticated状态设置为true。 - 第三次:
reloadPersonalInfo完成为时已晚并将authenticated状态设置为true(但路由器防护已阻止)。
有人可以帮忙吗?
edit 1:让我强调一下,重要的authenticated 状态是商店中的状态;它由这一行设置:this.store.dispatch({type: SET_AUTHENTICATED});。
编辑 2:我将条件从 authenticated 更改为 someCondition 以减少混淆。之前还有一个状态变量叫authenticated...
编辑 3:我已将 isAuthenticated() 方法的返回类型更改为 Observable<boolean> 而不是 boolean(按照 Martin 的建议)并调整了 canActivate 方法如下:
canActivate() {
return this.sessionService.isAuthenticated().map(isAuthenticated => {
if (isAuthenticated) {
return true;
}
this.router.navigate(['/signin']);
return false;
});
}
来自sessionService:
isAuthenticated(): Observable<boolean> {
return this.store.select(s => s.authenticated);
}
不幸的是,这没有什么区别......
有人可以建议如何解决这个异步问题吗?
【问题讨论】:
-
我必须想办法让
reloadPersonalInfo()在路由器保护运行之前完成...异步有时对我们来说很困难!!
标签: asynchronous angular rxjs angular2-routing ngrx