【问题标题】:How to handle Async Local Storage with Angular 2?如何使用 Angular 2 处理异步本地存储?
【发布时间】:2018-06-05 11:28:00
【问题描述】:

我正在使用角异步本地存储模块在本地存储中设置令牌的到期时间。

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

【问题讨论】:

  • 这个方法isAuthenticated()是在服务中还是在组件中?
  • 它在一个类中,即 @Injectable export class Foo { ... isAuthenticated() } 。这对我应该如何处理异步调用有影响吗?
  • 您介意显示更多此文件吗? @Injectable 应该是服务文件而不是组件文件。

标签: angular typescript asynchronous rxjs local-storage


【解决方案1】:

长话短说:在你的情况下,我会选择同步本地存储解决方案。

长篇大论:

在 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) 采用您建议的同步解决方案

最佳做法取决于具体情况。根据我的经验,如果您以可观察的方式进行操作,您最终将获得更多代码来处理所有可能和不可能的情况。此外,此代码的所有依赖项也必须异步调用(例如,如果您已登录,则发送 HTTP 请求,然后呈现其响应)。如果您想在 DRY 和服务中处理这类事情,您将不得不更深入地研究 RxJS 及其操作符,例如 MergeAll 等...

另一方面,如果您使用同步解决方案,您的代码会简单得多,但在某些情况下,您的应用程序可能会变得非常慢(想象一下 HTTP 请求在慢速移动网络上同步)。

因此,如果您只从 localStorage 获得一件小物品,您不会看到差异。另一方面,这个库为您提供了与 IndexedDb 相同的界面,其中最大限制为 could be 2Gb of data,因此您可以在那里保存整个集合,然后如果您使用异步方式,您的应用程序加速可能会很大。

【讨论】:

    【解决方案2】:

    我假设您的用户已经期望等待异步登录加载,因此您可以使用 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&lt;boolean&gt; 类型并返回时间戳。所以我把false改成了0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-04
      • 2018-01-22
      • 1970-01-01
      • 1970-01-01
      • 2018-04-28
      • 2020-11-03
      • 2019-05-25
      • 2017-05-31
      相关资源
      最近更新 更多