Is there a way to call .has(key) synchronously? #85
-
I expect there's a way to refactor my existing storage services, but I'm curious if there's an easier way to solve my issue, so forgive me if this turns into a ::headdesk:: moment for either of us. My workflow is typically as follows using a network first approach:
For performance reasons on data that changes very infrequently, I want to use a cache-first strategy:
My current code would adapt to this extremely easily if .has(key) was synchronous, but trying to manage multiple levels of asychronous logic while conforming to the Observable signature of the service method is making my head ache, and I'm not sure if I'm missing something obvious. I can't seem to use async/await in the service method as it returns an Observable, and I feel like there's a simple solution that I'm overlooking. Any thoughts would be appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
But it seems you just have a RxJS issue. ;) I'd need your code sample if you want some help. I'll close the issue for house-keeping as it's not an issue, but I'll continue to answer you. |
Beta Was this translation helpful? Give feedback.
-
Thanks - here's a stripped down (but complete) example of how I'm using local storage with on the fly encryption/decryption with a caching strategy. Most services are network first - if there's a network connection, fetch from the server and cache, if not, fetch from the cache, and if cached data isn't available, return an empty object. For the current requirement, I want to run cache first, so check to see if the data is cached, if so - return that, if not, fetch and cache, otherwise return an empty object. I can use hasKey provided I inject a setTimeout in the flow to give hasKey time to resolve, which makes me feel really dirty, but I can't quite wrap my head around the correct syntax to do this properly, so if you're able to provide some guidance that would be very much appreciated. I've included the encrypt/decrypt methods as well so you can get a complete sense of the implementation. Thanks!
|
Beta Was this translation helpful? Give feedback.
-
@alignsoft The basic answer is you need to chain your observables with It should look like this (after the declarations of your variables): const getFromStorage$ = this.localStorage.getItem('test', { schema }).pipe(
map((data) => decrypt(data)),
);
const getFromHttp$ = this.httpClient.get('test').pipe(
takeUntil(this.ngUnsubscribe),
delayWhen((data) => {
const checkedData = !data.error ? data : {};
const cryptedData = this.crypt ? this.encrypt(checkedData) : checkedData;
return this.localStorage.setItem('test', cryptedData);
}),
);
return this.localStorage.has(key).pipe(
switchMap((hasKey) => (!navigator.onLine || hasKey) ? getFromStorage$ : getFromHttp$)
); As a side note, start to use the full JSON schema syntax, ie. adding |
Beta Was this translation helpful? Give feedback.
-
Excellent! Thanks very much! |
Beta Was this translation helpful? Give feedback.
-
This works like an absolute charm, and has given me something new to learn more about. Thanks again! We're doing a production release early next week, and then there's a 30-day sprint to the next release during which time I'll be able to upgrade to v8 and make any adjustments necessary (schema's etc.) and test thoroughly - I'll provide feedback as soon as I get into that cycle. |
Beta Was this translation helpful? Give feedback.
@alignsoft The basic answer is you need to chain your observables with
switchMap()
.It should look like this (after the declarations of your variables):