Skip to content

Instantly share code, notes, and snippets.

@MichalZalecki
Last active July 20, 2021 23:37
Show Gist options
  • Select an option

  • Save MichalZalecki/70a831304b0e83afbc0fbad3e8577068 to your computer and use it in GitHub Desktop.

Select an option

Save MichalZalecki/70a831304b0e83afbc0fbad3e8577068 to your computer and use it in GitHub Desktop.
Simple sessionStorage/localStorage wrapper factory
import storageFactory from "./storageFactory";
export const localStore = storageFactory(localStorage);
export const sessionStore = storageFactory(sessionStorage);
/* ISC License (ISC). Copyright 2017 Michal Zalecki */
export function storageFactory(storage: Storage): Storage {
let inMemoryStorage: { [key: string]: string } = {};
const length = 0;
function isSupported() {
try {
const testKey = "__some_random_key_you_are_not_going_to_use__";
storage.setItem(testKey, testKey);
storage.removeItem(testKey);
return true;
} catch (e) {
return false;
}
}
function clear(): void {
if (isSupported()) {
storage.clear();
} else {
inMemoryStorage = {};
}
}
function getItem(name: string): string | null {
if (isSupported()) {
return storage.getItem(name);
}
if (inMemoryStorage.hasOwnProperty(name)) {
return inMemoryStorage[name];
}
return null;
}
function key(index: number): string | null {
if (isSupported()) {
return storage.key(index);
} else {
return Object.keys(inMemoryStorage)[index] || null;
}
}
function removeItem(name: string): void {
if (isSupported()) {
storage.removeItem(name);
} else {
delete inMemoryStorage[name];
}
}
function setItem(name: string, value: string): void {
if (isSupported()) {
storage.setItem(name, value);
} else {
inMemoryStorage[name] = String(value); // not everyone uses TypeScript
}
}
return {
getItem,
setItem,
removeItem,
clear,
key,
length,
};
}
@ZaLiTHkA
Copy link
Copy Markdown

just out of curiosity, wouldn't it be better to move the contents of isSupported out so it only runs once, rather than creating and then deleting __some_random_key_you_are_not_going_to_use__ at the start of every action?

for example:

function storageFactory(storage) {
  let inMemoryStorage = {}; 
  let browserStorageSupported;

  try {
    const key = "__some_random_key_you_are_not_going_to_use__";
    storage.setItem(key, key);
    storage.removeItem(key);
    browserStorageSupported = true;
  } catch (e) {
    browserStorageSupported = false;
  }

  function getItem(key) {
    if (browserStorageSupported) {
      return storage.getItem(key);
    }
    return inMemoryStorage[key] || null;
  }

  ...
}

@MichalZalecki
Copy link
Copy Markdown
Author

@MichalZalecki
Copy link
Copy Markdown
Author

@ZaLiTHkA Maybe, but I like function better than a "helper" variables.

@abereghici
Copy link
Copy Markdown

@ZaLiTHkA Maybe, but I like function better than a "helper" variables.

You can make isSupported function as closure and encapsulate that "helper' variable. In this way you won't write "some_random_key_you_are_not_going_to_use" key everytime when a function is called. Localstorage is synchronous and blocks the main thread.

@MichalZalecki
Copy link
Copy Markdown
Author

MichalZalecki commented Aug 26, 2020

To be strict, it's already in a closure, just not using variables outside its own function scope. Make it yours, adjust to your needs, if you have many reads/writes act accordingly. This was never my case and I don’t want to assume that if it worked once it’s going to work for each subsequent call. I imagine how the user can change settings during his visit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment