如何使用Angular 2处理异步本地存储?

时间:2018-06-04 23:01:21

标签: angular typescript asynchronous rxjs local-storage

我使用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本地存储模块。 但也许我需要的只是一个简单的同步本地存储模块?或者这被认为是不好的做法? 任何帮助都会非常感谢!

2 个答案:

答案 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()不能包含booleanObservable<boolean>类型并返回时间戳。所以我将false更改为0