Skip to content

Commit

Permalink
more efficient local storage & mem adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
mmalmi committed Sep 11, 2023
1 parent d7a7c75 commit 7145ebc
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/js/state/LocalState.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import LocalStorageMemoryAdapter from '@/state/LocalStorageMemoryAdapter.ts';

import Node from './Node';

const localState = new Node();
const localState = new Node({ adapters: [new LocalStorageMemoryAdapter()] });

export default localState;
80 changes: 80 additions & 0 deletions src/js/state/LocalStorageMemoryAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Adapter, Callback, NodeValue, Unsubscribe } from '@/state/types.ts';

export default class LocalStorageMemoryAdapter extends Adapter {
private storage = new Map<string, NodeValue>();
private isLoaded = false;
private loadingPromise: Promise<void>;
private resolveLoading: (() => void) | null = null;

constructor() {
super();
this.loadingPromise = new Promise((resolve) => {
this.resolveLoading = resolve;
});
this.loadFromLocalStorage();
}

private loadFromLocalStorage() {
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i) as string;
const value = JSON.parse(localStorage.getItem(key) || '') as NodeValue;
this.storage.set(key, value);
}
this.isLoaded = true;
if (this.resolveLoading) {
this.resolveLoading();
}
}

private listFromStorage(path: string, callback: Callback) {
for (const [storedPath, storedValue] of this.storage) {
const remainingPath = storedPath.replace(`${path}/`, '');
if (
storedPath.startsWith(`${path}/`) &&
remainingPath.length &&
!remainingPath.includes('/')
) {
callback(storedValue.value, storedPath, storedValue.updatedAt, () => {});
}
}
}

get(path: string, callback: Callback): Unsubscribe {
const storedValue = this.storage.get(path) || { value: undefined, updatedAt: undefined };
callback(storedValue.value, path, storedValue.updatedAt, () => {});

if (!this.isLoaded) {
this.loadingPromise.then(() => {
const updatedValue = this.storage.get(path) || { value: undefined, updatedAt: undefined };
if (updatedValue !== storedValue) {
callback(updatedValue.value, path, updatedValue.updatedAt, () => {});
}
});
}

return () => {};
}

async set(path: string, value: NodeValue) {
await this.loadingPromise;

if (value.updatedAt === undefined) {
throw new Error(`Invalid value: ${JSON.stringify(value)}`);
}

this.storage.set(path, value);
localStorage.setItem(path, JSON.stringify(value));
}

list(path: string, callback: Callback): Unsubscribe {
this.listFromStorage(path, callback);

if (!this.isLoaded) {
this.loadingPromise.then(() => {
this.listFromStorage(path, callback);
});
}

return () => {};
}
}

0 comments on commit 7145ebc

Please sign in to comment.