我使用angular async本地存储模块设置本地存储中令牌的到期时间。
import { AsyncLocalStorage } from 'angular-async-local-storage';
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
this.localStorage.setItem('expires_at', expiresAt).subscribe(() => {});
然后我有一个在用户登录时调用的函数,它会检查令牌是否仍然有效:
get isAuthenticated(): boolean {
let res;
this.localStorage.getItem('expires_at')
.subscribe((val) => {
let expiresAt = JSON.parse(val);
res = (expiresAt && this.loggedIn) ? (new Date().getTime() < expiresAt) : false;
});
return res;
}
这里的问题是localStorage.getItem()返回一个Observable。 因此,当我们在observable上调用.subscribe时,它被异步调用,这意味着我们不会阻塞直到结果准备就绪 因此代码直接执行并执行return res语句,此时res未定义,因为订阅箭头函数中的代码尚未执行,因为结果尚未就绪。
所以我需要一些关于解决这个问题的最佳方法的建议? 我想到的一种方法是尝试阻塞直到结果准备就绪,但这似乎是一种反模式,因为我们正在使用ASYNC本地存储模块。 但也许我需要的只是一个简单的同步本地存储模块?或者这被认为是不好的做法? 任何帮助都会非常感谢!
答案 0 :(得分:0)
长话短说:在你的情况下,我会使用同步本地存储解决方案。
长篇故事:
在Angular中这样的情况(同步与异步)我总是得到这两个解决方案中的一个:
1)让isAuthenticated返回Observable并映射你的localstorage observable以返回true / false
get isAuthenticated(): Observable<boolean> {
return this.localStorage.getItem('expires_at').pipe(
map((val) => {
let expiresAt = JSON.parse(val);
let res = (expiresAt && this.loggedIn) ? (new Date().getTime() < expiresAt) : false;
return res;
})
);
}
2)使用您提议的同步解决方案
最佳做法取决于具体情况。根据我的经验,如果你以可观察的方式做到这一点,你将最终得到更多的代码处理所有可能的&amp;不可能的情况此外,所有对此代码的依赖关系也必须异步调用(例如,如果您已登录,则发送HTTP请求然后呈现其响应)。如果你想处理这些干事和服务,你将不得不深入研究RxJS及其运营商,如MergeAll等......
另一方面,如果您使用同步解决方案,您的代码会更简单,但在某些情况下,您的应用程序会变得非常缓慢(想象在慢速移动网络上HTTP请求同步)。
因此,如果您只从localStorage获得一个小项目,那么您就不会看到差异。另一方面,这个库为IndexedDb提供了相同的接口,其中最大限制为could be 2Gb of data,因此您可以保存整个集合,然后如果您使用异步方式,您的应用程序加速可能会很大。
答案 1 :(得分:0)
我假设您的用户已经期望等待加载异步登录,因此您可以使用flatMap将localStorage调用链接到它:
isAuthenticated(): Observable<number> {
return this.localStorage.getItem('expires_at')
.map((val) => {
let expiresAt = JSON.parse(val);
return (expiresAt && this.loggedIn) ? (new Date().getTime() < expiresAt) : 0;
});
}
yourLoginFunction()
.flatMap(loginRes => {
return this.isAuthenticated()
})
.subscribe(res => {
// handle accordingly
}
请注意,isAuthenticated()
不能包含boolean
或Observable<boolean>
类型并返回时间戳。所以我将false
更改为0
。