0

我有一个 Angular 应用程序,它具有持久性存储和存储项的密钥列表。我想在应用程序启动时将已知键的值从持久存储异步加载到内存中,以便在应用程序运行时可以同步访问它们。所以我创建了一个 Observable,它遍历键列表的所有元素并附加一个管道,它应该获取每个元素的值并移交键和值的组合,因此我可以将它们存储在缓存中。应该捕获在持久存储中找不到值的情况。不幸的是,这仅适用于其中一个键。然后外部 Observable 意外完成。

通过查看日志,我可以看到,外部 Observable 正确地迭代了键列表的三个元素并运行了 switchMap()。但是只有一个值从持久存储中提取出来,并且在 localStorageService.get()-Observable 完成第一个元素之后,from-Observable 完成。

日志显示了这一点:

  • from() $.next => (2) ["authorizationDataIdToken", 1]
  • switchMap(): 键:authorizationDataIdToken
  • from() $.next => (2) ["_isAuthorized", 0]
  • switchMap(): 键: _isAuthorized
  • from() $.next => (2) ["userData", 0]
  • switchMap():键:用户数据
  • 来自() $.complete
  • localStorageService.get(userData) $.next => [object Object]
  • from() - 在 switchMap $.next => (2) ["userData", "[object Object]"] 之后
  • OIDC 存储:缓存键:userData,值:[object Object]
  • localStorageService.get(userData) $.complete
  • from() - 在 switchMap $.complete 之后
  • OIDC 存储:随时可用。

这是加载到缓存功能的代码:

private prepareForUsage() {
    // Take each element from the securely-stored-keys-list,
    // get their values from the secured storage and put them into the cache.
    from(Object.entries(this.keysStoredSecurely)).pipe(
        log('from()'),
        // At this point, we got the key and want to load the value from the local storage.
        // But we want to have both, key and value afterwards.
        switchMap(([key, protectionLevel]) => {
            console.log('switchMap(): key: ', key);
            // Here we try to fetch the value for the key via local storage service.
            return this.localStorageService.get(key, true).pipe(
                log(`localStorageService.get(${key})`),
                // Because the item we want to access might not exist yet, we could get an error, that we want to catch.
                catchError((error, _) => {
                    if (isDevMode()) { console.warn(`${error}, key: ${key}`); }
                    return of(undefined);
                }),
                // Here we have the value for the key and we want to combine both and return it.
                map(value => [key, value])
            );
        }),
        log('from() - after switchMap'),
    ).subscribe({
        // Put each item in the cache.
        next: ([key, value]) => {
            if (key === undefined || value === undefined) {
                if (isDevMode()) { console.log(`OIDC Storage: Key or value missing. key: ${key}, value: ${value}`); }
            } else {
                if (isDevMode()) { console.log(`OIDC Storage: Cache key: ${key}, value: ${value}`); }
                sessionStorage.setItem(key, value);
            }
        },
        error: (error) => {
            if (isDevMode()) { console.error(`OIDC Storage: ${error}`); }
        },
        // Declare the storage as ready for usage.
        complete: () => {
            if (isDevMode()) { console.log('OIDC Storage: ready for use.'); }
            this.isReadyForUsage.next(true);
        }
    });
}

这是本地存储服务的 get() 函数的签名:

get(key: string, encrypted: boolean = false): Observable<string>

我希望对 from-Observable 发出的每个元素都执行本地存储服务的 get() 函数的调用,但是我可以看到它只调用了一次并且不知道我做错了什么。

4

1 回答 1

0

好的,我发现了。问题是,from-Observable 发出的元素来得非常快,而 switchMap 的内部 Observable 只处理最后一个传入的元素并取消订阅之前的元素。将 switchMap() 更改为 mergeMap() 就可以了。

于 2019-07-23T07:45:26.247 回答